Code:
/ DotNET / DotNET / 8.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.Listprops = 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
- ISAPIApplicationHost.cs
- SqlInfoMessageEvent.cs
- AssemblyBuilder.cs
- ApplicationManager.cs
- DockAndAnchorLayout.cs
- ProfileEventArgs.cs
- CallContext.cs
- ColorConvertedBitmap.cs
- EdmType.cs
- BufferBuilder.cs
- UseManagedPresentationBindingElement.cs
- SessionIDManager.cs
- GrammarBuilderWildcard.cs
- ToolboxItemAttribute.cs
- AssemblyAttributes.cs
- _TransmitFileOverlappedAsyncResult.cs
- EncoderBestFitFallback.cs
- SqlInternalConnection.cs
- XmlSchemaValidator.cs
- PathParser.cs
- ErrorInfoXmlDocument.cs
- Bold.cs
- DynamicFilter.cs
- StateDesigner.CommentLayoutGlyph.cs
- FeatureSupport.cs
- RegexFCD.cs
- CngKeyCreationParameters.cs
- TypeToStringValueConverter.cs
- PreservationFileWriter.cs
- Wizard.cs
- AtlasWeb.Designer.cs
- DesignerOptionService.cs
- MaterialGroup.cs
- BitmapSizeOptions.cs
- DefaultMergeHelper.cs
- WebPartPersonalization.cs
- SmiContextFactory.cs
- SecurityCriticalDataForSet.cs
- StateFinalizationDesigner.cs
- ClientScriptManagerWrapper.cs
- TransformerInfo.cs
- ConstantProjectedSlot.cs
- TemplateControlCodeDomTreeGenerator.cs
- SoapSchemaExporter.cs
- SemanticBasicElement.cs
- SqlException.cs
- CommandBindingCollection.cs
- FragmentQueryProcessor.cs
- FontDriver.cs
- EventListenerClientSide.cs
- DiscriminatorMap.cs
- IInstanceTable.cs
- MobileComponentEditorPage.cs
- DataGridTextColumn.cs
- CodeCommentStatement.cs
- WebPartMenuStyle.cs
- DbProviderManifest.cs
- RelOps.cs
- XXXInfos.cs
- XmlILStorageConverter.cs
- DataSourceView.cs
- DrawingAttributesDefaultValueFactory.cs
- GenericEnumerator.cs
- VarInfo.cs
- AggregateNode.cs
- TrustLevel.cs
- EditableLabelControl.cs
- EntityContainerAssociationSet.cs
- XpsException.cs
- FreeFormDesigner.cs
- baseshape.cs
- SpellerHighlightLayer.cs
- InfoCardKeyedHashAlgorithm.cs
- Line.cs
- MDIControlStrip.cs
- KeyMatchBuilder.cs
- KeyInterop.cs
- PipelineModuleStepContainer.cs
- ComponentEditorPage.cs
- ViewStateException.cs
- DataDocumentXPathNavigator.cs
- CommandID.cs
- TrackPoint.cs
- TransformedBitmap.cs
- XmlDataLoader.cs
- _SslSessionsCache.cs
- WebUtility.cs
- KeyBinding.cs
- SqlClientMetaDataCollectionNames.cs
- SqlCacheDependencySection.cs
- SystemColors.cs
- FlowNode.cs
- TransformGroup.cs
- BufferBuilder.cs
- CharAnimationBase.cs
- ThumbButtonInfoCollection.cs
- OdbcEnvironmentHandle.cs
- ReadOnlyMetadataCollection.cs
- DragEvent.cs
- ImmutablePropertyDescriptorGridEntry.cs