Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Data / ObjectDataProvider.cs / 2 / ObjectDataProvider.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Implementation of ObjectDataProvider object. // // Specs: [....]/connecteddata/Specs/Avalon%20DataProviders.mht // //--------------------------------------------------------------------------- using System; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Windows.Threading; using System.Threading; using System.Windows; using System.Windows.Data; using MS.Internal; using MS.Internal.Data; // ParameterCollection using System.Windows.Markup; //--------------------------------------------------------------------------- // Design notes: // // ObjectDataProvider uses Activator.CreateInstance() to instantiate a new // ObjectInstance and Type.InvokeMember() to call a member on the object. // // Another way to write this class is through using ConstructorInfo and // MethodInfo, it would allow some nice things like caching the MemberInfo // and changing it only when the MethodParameters was changed in a // significant way. // However, it was discovered that Type.GetConstructorInfo() and // Type.GetMethodInfo() need to know all the types of the parameters for // member matching. This means that any null parameter may foil the match. // // By using Activator.CreateInstance() and Type.InvokeMember(), we get to // take advantage of more of the "magic" that finds the best matched // constructor/method with the given parameters. // // Security info: // // ObjectDataProvider will fail (as it should) when it does not have // permissions to perform reflection on the given Type or Member. //--------------------------------------------------------------------------- namespace System.Windows.Data { ////// The ObjectDataProvider class defines an object /// that instantiates a business object for use as a source for data binding. /// [Localizability(LocalizationCategory.NeverLocalize)] // Not localizable public class ObjectDataProvider : DataSourceProvider { //------------------------------------------------------ // // Constructors // //----------------------------------------------------- #region Constructors ////// Instantiates a new instance of a ObjectDataProvider /// public ObjectDataProvider() { _constructorParameters = new ParameterCollection(new ParameterCollectionChanged(OnParametersChanged)); _methodParameters = new ParameterCollection(new ParameterCollectionChanged(OnParametersChanged)); _sourceDataChangedHandler = new EventHandler(OnSourceDataChanged); } #endregion Constructors //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties ////// The type to instantiate for use as ObjectInstance. /// This is null when the ObjectDataProvider is uninitialized or explicitly set to null. /// If the user makes an assignment to ObjectInstance, ObjectType will return /// the Type of the object (or null if the object is null). /// ////// Only one of ObjectType or ObjectInstance can be set by the user to a non-null value. /// While refresh is deferred, ObjectInstance and Data will not update until Refresh() is called. /// public Type ObjectType { get { return _objectType; } set { // User is only allowed to set one of ObjectType or ObjectInstance. // To change "mode", the user must null the other property first. if (_mode == SourceMode.FromInstance) throw new InvalidOperationException(SR.Get(SRID.ObjectDataProviderCanHaveOnlyOneSource)); _mode = (value == null) ? SourceMode.NoSource : SourceMode.FromType; _constructorParameters.SetReadOnly(false); if (_needNewInstance = SetObjectType(value)) // raises property changed event { // Note: ObjectInstance and Data are not updated until Refresh() happens! if (! IsRefreshDeferred) Refresh(); } } } ////// This method is used by TypeDescriptor to determine if this property should /// be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeObjectType() { return (_mode == SourceMode.FromType) && (ObjectType != null); } ////// When ObjectType is set to a non-null value, this holds the /// instantiated object of the Type specified in ObjectType. /// If ObjectInstance is assigned by the user, ObjectType property will reflect the Type /// of the assigned object. /// If a DataSourceProvider is assigned to ObjectInstance, ObjectDataProvider will /// use the Data of the assigned source provider as its effective ObjectInstance. /// ////// The instance of object constructed from ObjectType and ConstructorParameters. -or- /// The DataSourceProvider whose Data is used as ObjectInstance. /// ////// Only one of ObjectType or ObjectInstance can be set by the user to a non-null value. /// This property, like the Data property, honors DeferRefresh: after setting the ObjectType, /// ObjectInstance will not be filled until Refresh() happens. /// public object ObjectInstance { get { return (_instanceProvider != null) ? _instanceProvider : _objectInstance; } set { // User is only allowed to set one of ObjectType or ObjectInstance. // To change mode, the user must null the property first. if (_mode == SourceMode.FromType) throw new InvalidOperationException(SR.Get(SRID.ObjectDataProviderCanHaveOnlyOneSource)); _mode = (value == null) ? SourceMode.NoSource : SourceMode.FromInstance; if (ObjectInstance == value) // instance or provider has not changed, do nothing { // debug-only sanity check, since GetType() isn't that cheap; // using _objectInstance because we're not trying to check the type of the provider! Debug.Assert((_objectInstance == null) ? (_objectType == null) : (_objectType == _objectInstance.GetType())); return; } if (value != null) { _constructorParameters.SetReadOnly(true); _constructorParameters.ClearInternal(); } else { _constructorParameters.SetReadOnly(false); } value = TryInstanceProvider(value); // returns the real instance // this also updates ObjectType if necessary: if (SetObjectInstance(value)) // raises property changed event { // Note: Data is not updated until Refresh() happens! if (! IsRefreshDeferred) Refresh(); } } } ////// This method is used by TypeDescriptor to determine if this property should /// be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeObjectInstance() { return (_mode == SourceMode.FromInstance) && (ObjectInstance != null); } ////// The name of the method to call on the specified type. /// [DefaultValue(null)] public string MethodName { get { return _methodName; } set { _methodName = value; OnPropertyChanged(s_method); if (!IsRefreshDeferred) Refresh(); } } ////// Parameters to pass to the Constructor /// ////// Changing this collection will implicitly cause this DataProvider to refresh. /// When changing multiple refresh-causing properties, the use of /// public IList ConstructorParameters { get { return _constructorParameters; } } ///is recommended. /// ConstuctorParameters becomes empty and read-only when /// ObjectInstance is assigned a value by the user. /// /// This method is used by TypeDescriptor to determine if this property should /// be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeConstructorParameters() { return (_mode == SourceMode.FromType) && (_constructorParameters.Count > 0); } ////// Parameters to pass to the Method /// ////// Changing this collection will implicitly cause this DataProvider to refresh. /// When changing multiple refresh-causing properties, the use of /// public IList MethodParameters { get { return _methodParameters; } } ///is recommended. /// /// This method is used by TypeDescriptor to determine if this property should /// be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeMethodParameters() { return _methodParameters.Count > 0; } ////// If true object creation will be performed in a worker /// thread, otherwise will be done in active context. /// [DefaultValue(false)] public bool IsAsynchronous { get { return _isAsynchronous; } set { _isAsynchronous = value; OnPropertyChanged(s_async); } } #endregion Public Properties //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Start instantiating the requested object, either immediately /// or on a background thread, see IsAsynchronous. /// Called by base class from InitialLoad or Refresh /// protected override void BeginQuery() { if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ProviderQuery)) { TraceData.Trace(TraceEventType.Warning, TraceData.BeginQuery( TraceData.Identify(this), IsAsynchronous ? "asynchronous" : "synchronous")); } if (IsAsynchronous) { ThreadPool.QueueUserWorkItem(new WaitCallback(QueryWorker), null); } else { QueryWorker(null); } } #endregion Protected Methods //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods // if the passed in value was a DataSourceProvider, // start listening to the (new) provider, and returns the instance value; // else just return the value. private object TryInstanceProvider(object value) { if (_instanceProvider != null) // was using provider for source { // stop listening to old provider _instanceProvider.DataChanged -= _sourceDataChangedHandler; } _instanceProvider = value as DataSourceProvider; if (_instanceProvider != null) { // start listening to new provider _instanceProvider.DataChanged += _sourceDataChangedHandler; value = _instanceProvider.Data; } return value; } // called from ObjectInstance setter or from source provider data change event handler; // raises property changed event; // return true iff ObjectInstance is changed private bool SetObjectInstance(object value) { // In FromType mode, _objectInstance is set in CreateObjectInstance() Debug.Assert(_mode != SourceMode.FromType); if (_objectInstance == value) return false; _objectInstance = value; // set the objectType by looking at the new value SetObjectType((value != null) ? value.GetType() : null); // raise this change event AFTER both oType and oInstance are updated OnPropertyChanged(s_instance); return true; } // raises property changed event; // return true iff ObjectType is changed private bool SetObjectType(Type newType) { if (_objectType != newType) { _objectType = newType; OnPropertyChanged(s_type); return true; } return false; } void QueryWorker(object obj) { object data = null; Exception e = null; // exception to pass back to main thread if (_mode == SourceMode.NoSource || _objectType == null) { if (TraceData.IsEnabled) TraceData.Trace(TraceEventType.Error, TraceData.ObjectDataProviderHasNoSource); e = new InvalidOperationException(SR.Get(SRID.ObjectDataProviderHasNoSource)); } else { Exception exInstantiation = null; if (_needNewInstance && (_mode == SourceMode.FromType)) { // check if there are public constructors before trying to instantiate; // this isn't cheap (and is redundant), but it should be better than throwing an exception. ConstructorInfo[] ciAry = _objectType.GetConstructors(); if (ciAry.Length != 0) { _objectInstance = CreateObjectInstance(out exInstantiation); } // don't try to instantiate again until type/parameters change _needNewInstance = false; } // keep going even if there's no ObjectInstance; method might be static. if (string.IsNullOrEmpty(MethodName)) { data = _objectInstance; } else { data = InvokeMethodOnInstance(out e); if (e != null && exInstantiation != null) { // if InvokeMethod failed, we prefer to surface the instantiation error, if any. // (although this can be confusing if the user wanted to call a static method) e = exInstantiation; } } } if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ProviderQuery)) { TraceData.Trace(TraceEventType.Warning, TraceData.QueryFinished( TraceData.Identify(this), Dispatcher.CheckAccess() ? "synchronous" : "asynchronous", TraceData.Identify(data), TraceData.IdentifyException(e))); } OnQueryFinished(data, e, null, null); } object CreateObjectInstance(out Exception e) { object instance = null; string error = null; // string that describes known error e = null; // PreSharp uses message numbers that the C# compiler doesn't know about. // Disable the C# complaints, per the PreSharp documentation. #pragma warning disable 1634, 1691 // PreSharp complains about catching NullReference (and other) exceptions. // It doesn't recognize that IsCriticalException() handles these correctly. #pragma warning disable 56500 Debug.Assert(_objectType != null); try { object[] parameters = new object[_constructorParameters.Count]; _constructorParameters.CopyTo(parameters, 0); instance = Activator.CreateInstance(_objectType, 0, null, parameters, System.Globalization.CultureInfo.InvariantCulture); OnPropertyChanged(s_instance); } catch (ArgumentException ae) { // this may fire when trying to create Context Affinity objects error = "Cannot create Context Affinity object."; e = ae; } catch (System.Runtime.InteropServices.COMException ce) { // this may fire due to marshalling issues error = "Marshaling issue detected."; e = ce; } catch (System.MissingMethodException mme) { // this may be due to setting parameters to a non parameter // only class contructor error = "Wrong parameters for constructor."; e = mme; } // Catch all exceptions. When there is no app code on the stack, // the exception isn't actionable by the app. // Yet we don't want to crash the app. catch (Exception ex) { if (CriticalExceptions.IsCriticalException(ex)) throw; error = null; // indicate unknown error e = ex; } catch // non CLS compliant exception { error = null; // indicate unknown error e = new InvalidOperationException(SR.Get(SRID.ObjectDataProviderNonCLSException, _objectType.Name)); } #pragma warning restore 56500 #pragma warning restore 1634, 1691 if (e != null || error != null) { // report known errors through TraceData (instead of throwing exceptions) if (TraceData.IsEnabled) TraceData.Trace(TraceEventType.Error, TraceData.ObjDPCreateFailed, _objectType.Name, error, e); // in async mode we pass all exceptions to main thread; // in sync mode we don't handle unknown exceptions. if (!IsAsynchronous && error == null) throw e; } return instance; } object InvokeMethodOnInstance(out Exception e) { object data = null; string error = null; // string that describes known error e = null; Debug.Assert(_objectType != null); object[] parameters = new object[_methodParameters.Count]; _methodParameters.CopyTo(parameters, 0); // PreSharp uses message numbers that the C# compiler doesn't know about. // Disable the C# complaints, per the PreSharp documentation. #pragma warning disable 1634, 1691 // PreSharp complains about catching NullReference (and other) exceptions. // It doesn't recognize that IsCriticalException() handles these correctly. #pragma warning disable 56500 try { data = _objectType.InvokeMember(MethodName, s_invokeMethodFlags, null, _objectInstance, parameters, System.Globalization.CultureInfo.InvariantCulture); } catch (ArgumentException ae) { error = "Parameter array contains a string that is a null reference."; e = ae; } catch (MethodAccessException mae) { error = "The specified member is a class initializer."; e = mae; } catch (MissingMethodException mme) { error = "No method was found with matching parameter signature."; e = mme; } catch (TargetException te) { error = "The specified member cannot be invoked on target."; e = te; } catch (AmbiguousMatchException ame) { error = "More than one method matches the binding criteria."; e = ame; } // Catch all exceptions. When there is no app code on the stack, // the exception isn't actionable by the app. // Yet we don't want to crash the app. catch (Exception ex) { if (CriticalExceptions.IsCriticalException(ex)) { throw; } error = null; // indicate unknown error e = ex; } catch //FXCop Fix: CatchNonClsCompliantExceptionsInGeneralHandlers { error = null; // indicate unknown error e = new InvalidOperationException(SR.Get(SRID.ObjectDataProviderNonCLSExceptionInvoke, MethodName, _objectType.Name)); } #pragma warning restore 56500 #pragma warning restore 1634, 1691 if (e != null || error != null) { // report known errors through TraceData (instead of throwing exceptions) if (TraceData.IsEnabled) TraceData.Trace(TraceEventType.Error, TraceData.ObjDPInvokeFailed, MethodName, _objectType.Name, error, e); // in async mode we pass all exceptions to main thread; // in sync mode we don't handle unknown exceptions. if (!IsAsynchronous && error == null) throw e; } return data; } // call-back function for the ParameterCollections private void OnParametersChanged(ParameterCollection sender) { // if the ConstructorParameters change, remember to instantiate a new object if (sender == _constructorParameters) { // sanity check: we shouldn't have ctor param changes in FromInstance mode Invariant.Assert (_mode != SourceMode.FromInstance); _needNewInstance = true; } // Note: ObjectInstance and Data are not updated until Refresh() happens! if (!IsRefreshDeferred) Refresh(); } // handler for DataChanged event of the instance's DataSourceProvider private void OnSourceDataChanged(object sender, EventArgs args) { Invariant.Assert(sender == _instanceProvider); if (SetObjectInstance(_instanceProvider.Data)) { // Note: Data is not updated until Refresh() happens! if (! IsRefreshDeferred) Refresh(); } } ////// Helper to raise a PropertyChanged event />). /// private void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } #endregion Private Methods //----------------------------------------------------- // // Private Types // //------------------------------------------------------ #region Private Types private enum SourceMode { NoSource, // can accept assignment to ObjectType or ObjectSource FromType, // can accept assignment only to ObjectType FromInstance, // can accept assignment only to ObjectInstance } #endregion Private Types //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields Type _objectType; object _objectInstance; string _methodName; DataSourceProvider _instanceProvider; ParameterCollection _constructorParameters; ParameterCollection _methodParameters; bool _isAsynchronous = false; SourceMode _mode = SourceMode.NoSource; bool _needNewInstance = true; // set to true when ObjectType or ConstructorParameters change EventHandler _sourceDataChangedHandler; const string s_instance = "ObjectInstance"; const string s_type = "ObjectType"; const string s_method = "MethodName"; const string s_async = "IsAsynchronous"; const BindingFlags s_invokeMethodFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy | BindingFlags.OptionalParamBinding; #endregion Private Fields } } // 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
- ColorPalette.cs
- KeyConstraint.cs
- Attributes.cs
- RelationHandler.cs
- KoreanLunisolarCalendar.cs
- DataGridViewColumnConverter.cs
- FastEncoderStatics.cs
- DataGridViewBand.cs
- EventSinkHelperWriter.cs
- CompressedStack.cs
- UIElement.cs
- ReadOnlyCollectionBase.cs
- AuthenticationModulesSection.cs
- StyleSelector.cs
- TabItem.cs
- FormViewUpdateEventArgs.cs
- Rijndael.cs
- StaticContext.cs
- Scene3D.cs
- PropertyKey.cs
- SqlMethods.cs
- OleDbPropertySetGuid.cs
- ProjectionPlanCompiler.cs
- SchemaDeclBase.cs
- StylusSystemGestureEventArgs.cs
- ExpressionBinding.cs
- ConnectivityStatus.cs
- WindowsComboBox.cs
- EncoderNLS.cs
- PrePostDescendentsWalker.cs
- Point4DConverter.cs
- Point.cs
- DotAtomReader.cs
- DataGridViewCellValidatingEventArgs.cs
- ArgumentException.cs
- IndexedEnumerable.cs
- MessageHeaderT.cs
- NamespaceMapping.cs
- StringReader.cs
- EntityClassGenerator.cs
- TabRenderer.cs
- Rotation3DAnimationUsingKeyFrames.cs
- Point3DKeyFrameCollection.cs
- AutomationProperties.cs
- OdbcInfoMessageEvent.cs
- ExpressionCopier.cs
- ToolStripContainer.cs
- UpdatePanelTriggerCollection.cs
- ConstraintManager.cs
- SamlAssertion.cs
- BlockUIContainer.cs
- DataGridColumnHeaderCollection.cs
- Transactions.cs
- ObjRef.cs
- SingleSelectRootGridEntry.cs
- Geometry.cs
- BlurBitmapEffect.cs
- RequestCachePolicy.cs
- DSASignatureDeformatter.cs
- MetadataItemCollectionFactory.cs
- FlowPanelDesigner.cs
- BuildDependencySet.cs
- FreezableCollection.cs
- Image.cs
- BulletedList.cs
- SqlDataSourceStatusEventArgs.cs
- CompressedStack.cs
- XamlToRtfParser.cs
- ToolStripContentPanelRenderEventArgs.cs
- Parser.cs
- Method.cs
- Shape.cs
- DebugView.cs
- MessageSecurityException.cs
- ModuleConfigurationInfo.cs
- MouseButton.cs
- SchemaLookupTable.cs
- WindowsAuthenticationEventArgs.cs
- ClientTargetSection.cs
- NullableLongSumAggregationOperator.cs
- InplaceBitmapMetadataWriter.cs
- SharedPersonalizationStateInfo.cs
- PersonalizationDictionary.cs
- TabletCollection.cs
- Compiler.cs
- ColumnResult.cs
- Graphics.cs
- SynchronizationHandlesCodeDomSerializer.cs
- StylusTip.cs
- Helper.cs
- DataGridAutomationPeer.cs
- StringExpressionSet.cs
- SimpleTypeResolver.cs
- PngBitmapDecoder.cs
- RelationshipEntry.cs
- HttpServerVarsCollection.cs
- PrivateFontCollection.cs
- SqlDataReaderSmi.cs
- SubstitutionList.cs
- dataSvcMapFileLoader.cs