Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Data / ObjectDataProvider.cs / 1305600 / ObjectDataProvider.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Implementation of ObjectDataProvider object. // // Specs: http://avalon/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 IsCritical[Application]Exception() 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.IsCriticalApplicationException(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 [....] 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 IsCritical[Application]Exception() 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.IsCriticalApplicationException(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 [....] 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
- ProfessionalColorTable.cs
- BorderGapMaskConverter.cs
- XPathNodeHelper.cs
- FlowDocumentPage.cs
- OdbcParameter.cs
- WebPartConnectionsCloseVerb.cs
- FileUpload.cs
- AnonymousIdentificationSection.cs
- Matrix3DValueSerializer.cs
- X500Name.cs
- RowBinding.cs
- DataGridHelper.cs
- WindowPattern.cs
- CompilerTypeWithParams.cs
- EventDescriptor.cs
- GeneralTransform.cs
- ColumnClickEvent.cs
- UserNamePasswordValidationMode.cs
- DbParameterHelper.cs
- DataGridViewAdvancedBorderStyle.cs
- ProtectedProviderSettings.cs
- HierarchicalDataBoundControl.cs
- WinFormsSpinner.cs
- GroupBoxDesigner.cs
- GuidelineCollection.cs
- ObjectSecurityT.cs
- DynamicPropertyHolder.cs
- XdrBuilder.cs
- CultureMapper.cs
- ReverseQueryOperator.cs
- FormView.cs
- TreeNodeStyleCollection.cs
- SubMenuStyleCollection.cs
- StringArrayConverter.cs
- ContractReference.cs
- KnownTypes.cs
- IMembershipProvider.cs
- SoapBinding.cs
- PrintPreviewGraphics.cs
- XmlDownloadManager.cs
- InkCanvas.cs
- TdsRecordBufferSetter.cs
- HttpValueCollection.cs
- TextTreeInsertUndoUnit.cs
- PrintPreviewControl.cs
- XmlMapping.cs
- DnsEndpointIdentity.cs
- EventHandlerService.cs
- DatePickerAutomationPeer.cs
- BmpBitmapEncoder.cs
- Enumerable.cs
- TextEditor.cs
- MetaType.cs
- XamlRtfConverter.cs
- CodeDomLoader.cs
- ValueQuery.cs
- ThemeInfoAttribute.cs
- AllowedAudienceUriElementCollection.cs
- LogWriteRestartAreaAsyncResult.cs
- PlacementWorkspace.cs
- TextParaClient.cs
- FeatureAttribute.cs
- TagPrefixAttribute.cs
- ProfileSection.cs
- KeyPullup.cs
- WinInet.cs
- ServiceDiscoveryBehavior.cs
- GlobalizationAssembly.cs
- OutputCache.cs
- ContextBase.cs
- UIElement.cs
- XmlHelper.cs
- StateChangeEvent.cs
- XmlElementCollection.cs
- DesignSurfaceCollection.cs
- RangeValuePatternIdentifiers.cs
- SessionStateUtil.cs
- ImmutableObjectAttribute.cs
- ParallelTimeline.cs
- PrimitiveList.cs
- TypeBrowser.xaml.cs
- SqlClientPermission.cs
- EditorPartDesigner.cs
- PropertyConverter.cs
- SyndicationElementExtension.cs
- CipherData.cs
- Permission.cs
- ContentFileHelper.cs
- ScriptManager.cs
- QueryReaderSettings.cs
- MediaScriptCommandRoutedEventArgs.cs
- DataGridViewColumnEventArgs.cs
- PhoneCall.cs
- XmlTextWriter.cs
- TabControlToolboxItem.cs
- ListItemConverter.cs
- AlgoModule.cs
- RequestValidator.cs
- ErrorsHelper.cs
- TrailingSpaceComparer.cs