Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / Host / EventBindingService.cs / 1 / EventBindingService.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
namespace System.ComponentModel.Design {
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Design;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Microsoft.Internal.Performance;
using System.Windows.Forms;
///
///
/// This class provides a default implementation of the event
/// binding service.
///
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")]
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
public abstract class EventBindingService : IEventBindingService {
private Hashtable _eventProperties;
private IServiceProvider _provider;
private IComponent showCodeComponent;
private EventDescriptor showCodeEventDescriptor;
private string showCodeMethodName;
private static CodeMarkers codemarkers = CodeMarkers.Instance;
///
///
/// You must provide a service provider to the binding
/// service.
///
protected EventBindingService(IServiceProvider provider) {
if (provider == null) {
throw new ArgumentNullException("provider");
}
_provider = provider;
}
///
///
/// Creates a unique method name. The name must be
/// compatible with the script language being used and
/// it must not conflict with any other name in the user's
/// code.
///
protected abstract string CreateUniqueMethodName(IComponent component, EventDescriptor e);
///
///
/// This provides a notification that a particular method
/// is no longer being used by an event handler. Some implementations
/// may want to remove the event hander when no events are using
/// it. By overriding UseMethod and FreeMethod, an implementation
/// can know when a method is no longer needed.
///
protected virtual void FreeMethod(IComponent component, EventDescriptor e, string methodName) {
}
///
///
/// Returns a collection of strings. Each string is
/// the method name of a method whose signature is
/// compatible with the delegate contained in the
/// event descriptor. This should return an empty
/// collection if no names are compatible.
///
protected abstract ICollection GetCompatibleMethods(EventDescriptor e);
///
/// Generates a key based on a method name and it's parameters by just concatenating the
/// parameters.
///
private string GetEventDescriptorHashCode(EventDescriptor eventDesc) {
StringBuilder builder = new StringBuilder(eventDesc.Name);
builder.Append(eventDesc.EventType.GetHashCode().ToString(CultureInfo.InvariantCulture));
foreach(Attribute a in eventDesc.Attributes) {
builder.Append(a.GetHashCode().ToString(CultureInfo.InvariantCulture));
}
return builder.ToString();
}
///
///
/// Gets the requested service from our service provider.
///
protected object GetService(Type serviceType) {
if (_provider != null) {
return _provider.GetService(serviceType);
}
return null;
}
///
///
/// Shows the user code. This method does not show any
/// particular code; generally it shows the last code the
/// user typed. This returns true if it was possible to
/// show the code, or false if not.
///
protected abstract bool ShowCode();
///
///
/// Shows the user code at the given line number. Line
/// numbers are one-based. This returns true if it was
/// possible to show the code, or false if not.
///
protected abstract bool ShowCode(int lineNumber);
///
///
/// Shows the body of the user code with the given method
/// name. This returns true if it was possible to show
/// the code, or false if not.
///
protected abstract bool ShowCode(IComponent component, EventDescriptor e, string methodName);
///
///
/// This provides a notification that a particular method
/// is being used by an event handler. Some implementations
/// may want to remove the event hander when no events are using
/// it. By overriding UseMethod and FreeMethod, an implementation
/// can know when a method is no longer needed.
///
protected virtual void UseMethod(IComponent component, EventDescriptor e, string methodName) {
}
///
///
/// This validates that the provided method name is valid for
/// the language / script being used. The default does nothing.
/// You may override this and throw an exception if the name
/// is invalid for your use.
///
protected virtual void ValidateMethodName(string methodName) {
}
///
///
/// This creates a name for an event handling method for the given component
/// and event. The name that is created is guaranteed to be unique in the user's source
/// code.
///
string IEventBindingService.CreateUniqueMethodName(IComponent component, EventDescriptor e) {
if (component == null) {
throw new ArgumentNullException("component");
}
if (e == null) {
throw new ArgumentNullException("e");
}
return CreateUniqueMethodName(component, e);
}
///
///
/// Retrieves a collection of strings. Each string is the name of a method
/// in user code that has a signature that is compatible with the given event.
///
ICollection IEventBindingService.GetCompatibleMethods(EventDescriptor e) {
if (e == null) {
throw new ArgumentNullException("e");
}
return GetCompatibleMethods(e);
}
///
///
/// For properties that are representing events, this will return the event
/// that the property represents.
///
EventDescriptor IEventBindingService.GetEvent(PropertyDescriptor property) {
if (property is EventPropertyDescriptor) {
return ((EventPropertyDescriptor)property).Event;
}
return null;
}
///
/// returns true if the given event has a generic argument or return value in its raise method.
///
private bool HasGenericArgument(EventDescriptor ed) {
if (ed == null || ed.ComponentType == null) {
return false;
}
System.Reflection.EventInfo evInfo = ed.ComponentType.GetEvent(ed.Name);
if (evInfo == null || !evInfo.EventHandlerType.IsGenericType) {
return false;
}
Type[] args = evInfo.EventHandlerType.GetGenericArguments();
if (args != null && args.Length > 0) {
for (int i = 0; i < args.Length; i++) {
if (args[i].IsGenericType) {
return true;
}
}
}
return false;
}
///
///
/// Converts a set of events to a set of properties.
///
PropertyDescriptorCollection IEventBindingService.GetEventProperties(EventDescriptorCollection events) {
if (events == null) {
throw new ArgumentNullException("events");
}
System.Collections.Generic.List props = new System.Collections.Generic.List(events.Count);
// We cache the property descriptors here for speed. Create those for
// events that we don't have yet.
//
if (_eventProperties == null) {
_eventProperties = new Hashtable();
}
for (int i = 0; i < events.Count; i++) {
if (HasGenericArgument(events[i])) {
continue;
}
object eventHashCode = GetEventDescriptorHashCode(events[i]);
PropertyDescriptor prop = (PropertyDescriptor)_eventProperties[eventHashCode];
if (prop == null) {
prop = new EventPropertyDescriptor(events[i], this);
_eventProperties[eventHashCode] = prop;
}
props.Add(prop);
}
return new PropertyDescriptorCollection(props.ToArray());
}
///
///
/// Converts a single event to a property.
///
PropertyDescriptor IEventBindingService.GetEventProperty(EventDescriptor e) {
if (e == null) {
throw new ArgumentNullException("e");
}
if (_eventProperties == null) {
_eventProperties = new Hashtable();
}
object eventHashCode = GetEventDescriptorHashCode(e);
PropertyDescriptor prop = (PropertyDescriptor)_eventProperties[eventHashCode];
if (prop == null) {
prop = new EventPropertyDescriptor(e, this);
_eventProperties[eventHashCode] = prop;
}
return prop;
}
///
///
/// Displays the user code for this designer. This will return true if the user
/// code could be displayed, or false otherwise.
///
bool IEventBindingService.ShowCode() {
return ShowCode();
}
///
///
/// Displays the user code for the designer. This will return true if the user
/// code could be displayed, or false otherwise.
///
bool IEventBindingService.ShowCode(int lineNumber) {
return ShowCode(lineNumber);
}
///
///
/// Displays the user code for the given event. This will return true if the user
/// code could be displayed, or false otherwise.
///
bool IEventBindingService.ShowCode(IComponent component, EventDescriptor e) {
if (component == null) {
throw new ArgumentNullException("component");
}
if (e == null) {
throw new ArgumentNullException("e");
}
PropertyDescriptor prop = ((IEventBindingService)this).GetEventProperty(e);
string methodName = (string)prop.GetValue(component);
if (methodName == null) {
return false; // the event is not bound to a method.
}
Debug.Assert(showCodeComponent == null && showCodeEventDescriptor == null && showCodeMethodName == null, "show code already pending");
showCodeComponent = component;
showCodeEventDescriptor = e;
showCodeMethodName = methodName;
Application.Idle += new EventHandler(this.ShowCodeIdle);
return true;
}
///
///
/// Displays the user code for the given event. This will return true if the user
/// code could be displayed, or false otherwise.
///
private void ShowCodeIdle(object sender, EventArgs e) {
Application.Idle -= new EventHandler(this.ShowCodeIdle);
try {
ShowCode(showCodeComponent, showCodeEventDescriptor, showCodeMethodName);
}
finally {
showCodeComponent = null;
showCodeEventDescriptor = null;
showCodeMethodName = null;
codemarkers.CodeMarker(CodeMarkerEvent.perfFXDesignShowCode);
}
}
///
/// This is an EventDescriptor cleverly wrapped in a PropertyDescriptor
/// of type String. Note that we now handle subobjects by storing their
/// event information in their base component's site's dictionary.
/// Note also that when a value is set for this property we will code-gen
/// the event method. If the property is set to a new value we will
/// remove the old event method ONLY if it is empty.
///
private class EventPropertyDescriptor : PropertyDescriptor {
private EventDescriptor _eventDesc;
private EventBindingService _eventSvc;
private TypeConverter _converter;
///
/// Creates a new EventPropertyDescriptor.
///
internal EventPropertyDescriptor(EventDescriptor eventDesc, EventBindingService eventSvc) : base(eventDesc, null) {
_eventDesc = eventDesc;
_eventSvc = eventSvc;
}
///
/// Indicates whether reset will change the value of the component. If there
/// is a DefaultValueAttribute, then this will return true if getValue returns
/// something different than the default value. If there is a reset method and
/// a shouldPersist method, this will return what shouldPersist returns.
/// If there is just a reset method, this always returns true. If none of these
/// cases apply, this returns false.
///
public override bool CanResetValue(object component) {
return GetValue(component) != null;
}
///
/// Retrieves the type of the component this PropertyDescriptor is bound to.
///
public override Type ComponentType {
get {
return _eventDesc.ComponentType;
}
}
///
/// Retrieves the type converter for this property.
///
public override TypeConverter Converter {
get {
if (_converter == null) {
_converter = new EventConverter(_eventDesc);
}
return _converter;
}
}
///
/// Retrieves the event descriptor we are representing.
///
internal EventDescriptor Event {
get {
return _eventDesc;
}
}
///
/// Indicates whether this property is read only.
///
public override bool IsReadOnly {
get {
return Attributes[typeof(ReadOnlyAttribute)].Equals(ReadOnlyAttribute.Yes);
}
}
///
/// Retrieves the type of the property.
///
public override Type PropertyType {
get {
return _eventDesc.EventType;
}
}
///
/// Retrieves the current value of the property on component,
/// invoking the getXXX method. An exception in the getXXX
/// method will pass through.
///
public override object GetValue(object component) {
if (component == null) {
throw new ArgumentNullException("component");
}
// We must locate the sited component, because we store data on the dictionary
// service for the component.
//
ISite site = null;
if (component is IComponent) {
site = ((IComponent)component).Site;
}
if (site == null) {
IReferenceService rs = _eventSvc._provider.GetService(typeof(IReferenceService)) as IReferenceService;
if (rs != null) {
IComponent baseComponent = rs.GetComponent(component);
if (baseComponent != null) {
site = baseComponent.Site;
}
}
}
if (site == null) {
// Object not sited, so we weren't able to set a value on it. Setting
// a value will fail.
return null;
}
IDictionaryService ds = (IDictionaryService)site.GetService(typeof(IDictionaryService));
if (ds == null) {
// No dictionary service, so we weren't able to set a value on it. Setting
// a value will fail.
return null;
}
return (string)ds.GetValue(new ReferenceEventClosure(component, this));
}
///
/// Will reset the default value for this property on the component. If
/// there was a default value passed in as a DefaultValueAttribute, that
/// value will be set as the value of the property on the component. If
/// there was no default value passed in, a ResetXXX method will be looked
/// for. If one is found, it will be invoked. If one is not found, this
/// is a nop.
///
public override void ResetValue(object component) {
SetValue(component, null);
}
///
/// This will set value to be the new value of this property on the
/// component by invoking the setXXX method on the component. If the
/// value specified is invalid, the component should throw an exception
/// which will be passed up. The component designer should design the
/// property so that getXXX following a setXXX should return the value
/// passed in if no exception was thrown in the setXXX call.
///
public override void SetValue(object component, object value) {
// Argument, state checking. Is it ok to set this event?
//
if (IsReadOnly) {
Exception ex = new InvalidOperationException(SR.GetString(SR.EventBindingServiceEventReadOnly, Name));
ex.HelpLink = SR.EventBindingServiceEventReadOnly;
throw ex;
}
if (value != null && !(value is string)) {
Exception ex = new ArgumentException(SR.GetString(SR.EventBindingServiceBadArgType, Name, typeof(string).Name));
ex.HelpLink = SR.EventBindingServiceBadArgType;
throw ex;
}
string name = (string)value;
if (name != null && name.Length == 0) {
name = null;
}
// Obtain the site for the component. Note that this can be a site
// to a parent component if we can get to the reference service.
//
ISite site = null;
if (component is IComponent) {
site = ((IComponent)component).Site;
}
if (site == null) {
IReferenceService rs = _eventSvc._provider.GetService(typeof(IReferenceService)) as IReferenceService;
if (rs != null) {
IComponent baseComponent = rs.GetComponent(component);
if (baseComponent != null) {
site = baseComponent.Site;
}
}
}
if (site == null) {
Exception ex = new InvalidOperationException(SR.GetString(SR.EventBindingServiceNoSite));
ex.HelpLink = SR.EventBindingServiceNoSite;
throw ex;
}
// The dictionary service is where we store the actual event method name.
//
IDictionaryService ds = site.GetService(typeof(IDictionaryService)) as IDictionaryService;
if (ds == null) {
Exception ex = new InvalidOperationException(SR.GetString(SR.EventBindingServiceMissingService, typeof(IDictionaryService).Name));
ex.HelpLink = SR.EventBindingServiceMissingService;
throw ex;
}
// Get the old method name, ensure that they are different, and then continue.
//
ReferenceEventClosure key = new ReferenceEventClosure(component, this);
string oldName = (string)ds.GetValue(key);
if (object.ReferenceEquals(oldName, name)) {
return;
}
if (oldName != null && name != null && oldName.Equals(name)) {
return;
}
// Before we continue our work, ensure that the name is
// actually valid.
//
if (name != null) {
_eventSvc.ValidateMethodName(name);
}
// If there is a designer host, create a transaction so there is a
// nice name for this change. We don't want a name like
// "Change property 'Click', because to users, this isn't a property.
//
IDesignerHost host = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
DesignerTransaction trans = null;
if (host != null) {
trans = host.CreateTransaction(SR.GetString(SR.EventBindingServiceSetValue, site.Name, name));
}
try {
// Ok, the names are different. Fire a changing event to make
// sure it's OK to perform the change.
//
IComponentChangeService change = site.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
if (change != null) {
try{
change.OnComponentChanging(component, this);
change.OnComponentChanging(component, Event);
}
catch(CheckoutException coEx){
if (coEx == CheckoutException.Canceled){
return;
}
throw;
}
}
// Less chance of success of adding a new method name, so
// don't release the old name until we verify that adding
// the new one actually succeeded.
//
if (name != null) {
_eventSvc.UseMethod((IComponent)component, _eventDesc, name);
}
if (oldName != null) {
_eventSvc.FreeMethod((IComponent)component, _eventDesc, oldName);
}
ds.SetValue(key, name);
if (change != null) {
change.OnComponentChanged(component, Event, null, null);
change.OnComponentChanged(component, this, oldName, name);
}
OnValueChanged(component, EventArgs.Empty);
if (trans != null) {
trans.Commit();
}
}
finally {
if (trans != null) {
((IDisposable)trans).Dispose();
}
}
}
///
/// Indicates whether the value of this property needs to be persisted. In
/// other words, it indicates whether the state of the property is distinct
/// from when the component is first instantiated. If there is a default
/// value specified in this PropertyDescriptor, it will be compared against the
/// property's current value to determine this. If there is't, the
/// shouldPersistXXX method is looked for and invoked if found. If both
/// these routes fail, true will be returned.
///
/// If this returns false, a tool should not persist this property's value.
///
public override bool ShouldSerializeValue(object component) {
return CanResetValue(component);
}
///
/// Implements a type converter for event objects.
///
private class EventConverter : TypeConverter {
private EventDescriptor _evt;
///
/// Creates a new EventConverter.
///
internal EventConverter(EventDescriptor evt) {
_evt = evt;
}
///
/// Determines if this converter can convert an object in the given source
/// type to the native type of the converter.
///
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
if (sourceType == typeof(string)) {
return true;
}
return base.CanConvertFrom(context, sourceType);
}
///
/// Determines if this converter can convert an object to the given destination
/// type.
///
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
if (destinationType == typeof(string)) {
return true;
}
return base.CanConvertTo(context, destinationType);
}
///
/// Converts the given object to the converter's native type.
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
if (value == null) {
return value;
}
if (value is string) {
if (((string)value).Length == 0) {
return null;
}
return value;
}
return base.ConvertFrom(context, culture, value);
}
///
/// Converts the given object to another type. The most common types to convert
/// are to and from a string object. The default implementation will make a call
/// to ToString on the object if the object is valid and if the destination
/// type is string. If this cannot convert to the desitnation type, this will
/// throw a NotSupportedException.
///
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
if (destinationType == typeof(string)) {
return value == null ? string.Empty : value;
}
return base.ConvertTo(context, culture, value, destinationType);
}
///
/// Retrieves a collection containing a set of standard values
/// for the data type this validator is designed for. This
/// will return null if the data type does not support a
/// standard set of values.
///
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
// We cannot cache this because it depends on the contents of the source file.
//
string[] eventMethods = null;
if (context != null) {
IEventBindingService ebs = (IEventBindingService)context.GetService(typeof(IEventBindingService));
if (ebs != null) {
ICollection methods = ebs.GetCompatibleMethods(_evt);
eventMethods = new string[methods.Count];
int i = 0;
foreach(string s in methods) {
eventMethods[i++] = s;
}
}
}
return new StandardValuesCollection(eventMethods);
}
///
/// Determines if the list of standard values returned from
/// GetStandardValues is an exclusive list. If the list
/// is exclusive, then no other values are valid, such as
/// in an enum data type. If the list is not exclusive,
/// then there are other valid values besides the list of
/// standard values GetStandardValues provides.
///
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
return false;
}
///
/// Determines if this object supports a standard set of values
/// that can be picked from a list.
///
public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
return true;
}
}
///
/// This is a combination of a reference and a property, so that it can be used
/// as the key of a hashtable. This is because we may have subobjects that share
/// the same property.
///
private class ReferenceEventClosure {
object reference;
EventPropertyDescriptor propertyDescriptor;
public ReferenceEventClosure(object reference, EventPropertyDescriptor prop) {
this.reference = reference;
this.propertyDescriptor = prop;
}
public override int GetHashCode() {
return reference.GetHashCode() * propertyDescriptor.GetHashCode();
}
public override bool Equals(Object otherClosure) {
if (otherClosure is ReferenceEventClosure) {
ReferenceEventClosure typedClosure = (ReferenceEventClosure) otherClosure;
return(typedClosure.reference == reference &&
typedClosure.propertyDescriptor.Equals(propertyDescriptor));
}
return false;
}
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- InheritanceContextHelper.cs
- ConfigurationConverterBase.cs
- EmbossBitmapEffect.cs
- Validator.cs
- UserControlDocumentDesigner.cs
- _HTTPDateParse.cs
- GridViewUpdatedEventArgs.cs
- LabelLiteral.cs
- ScrollBarAutomationPeer.cs
- DeclaredTypeElementCollection.cs
- SpotLight.cs
- WebRequestModuleElementCollection.cs
- TextBoxRenderer.cs
- XmlSchemaSimpleContent.cs
- DataServiceQueryException.cs
- QueryStringParameter.cs
- XsdValidatingReader.cs
- Stylesheet.cs
- PageClientProxyGenerator.cs
- AspCompat.cs
- Expression.cs
- Deserializer.cs
- ExpressionList.cs
- RenderingBiasValidation.cs
- SoapFault.cs
- TemplateBindingExpressionConverter.cs
- TraceSwitch.cs
- InfoCardSymmetricCrypto.cs
- SecurityStandardsManager.cs
- InstancePersistenceCommand.cs
- NameTable.cs
- XmlParserContext.cs
- GridViewRowPresenterBase.cs
- Membership.cs
- BuildManagerHost.cs
- Resources.Designer.cs
- SpellerHighlightLayer.cs
- DataGridCaption.cs
- HelloOperationCD1AsyncResult.cs
- SafeEventHandle.cs
- Size.cs
- StreamingContext.cs
- SEHException.cs
- TextBox.cs
- LoadRetryStrategyFactory.cs
- GradientStop.cs
- XamlSerializationHelper.cs
- BoundColumn.cs
- DBCSCodePageEncoding.cs
- TextElementEnumerator.cs
- EditingCoordinator.cs
- StyleXamlParser.cs
- DataGridItemCollection.cs
- TreeNodeConverter.cs
- PerspectiveCamera.cs
- CodeDomConfigurationHandler.cs
- WmfPlaceableFileHeader.cs
- XmlSchemaParticle.cs
- HttpRequestCacheValidator.cs
- TrustLevel.cs
- ClientOptions.cs
- IISUnsafeMethods.cs
- StatusBarPanel.cs
- DefaultObjectMappingItemCollection.cs
- CodeSpit.cs
- StrongNameKeyPair.cs
- HostSecurityManager.cs
- URLIdentityPermission.cs
- HtmlForm.cs
- FileSystemEventArgs.cs
- VSDExceptions.cs
- SchemaImporterExtensionsSection.cs
- PriorityQueue.cs
- documentsequencetextcontainer.cs
- GradientBrush.cs
- InheritanceAttribute.cs
- ObjectPropertyMapping.cs
- InputProcessorProfilesLoader.cs
- _UncName.cs
- ContentControl.cs
- FunctionParameter.cs
- InArgument.cs
- XmlNamedNodeMap.cs
- HttpWebRequestElement.cs
- GridViewRowPresenter.cs
- EndOfStreamException.cs
- LinearGradientBrush.cs
- CultureNotFoundException.cs
- CssTextWriter.cs
- CodeAssignStatement.cs
- ClientScriptManagerWrapper.cs
- WebServiceData.cs
- CodeValidator.cs
- XmlLanguage.cs
- OneOfConst.cs
- EqualityArray.cs
- WindowsToolbar.cs
- ScrollProperties.cs
- TextSpan.cs
- InternalMappingException.cs