Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / System / Windows / Data / DataSourceProvider.cs / 1 / DataSourceProvider.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: common base class and contract for data source provider objects // // Specs: http://avalon/connecteddata/Specs/Avalon%20DataProviders.mht // //--------------------------------------------------------------------------- using System; using System.Diagnostics; using System.ComponentModel; using System.Threading; using System.Windows.Threading; // Dispatcher* using MS.Internal; // Invariant namespace System.Windows.Data { ////// Common base class and contract for data source providers. /// A DataProvider in Avalon is the factory that executes some query /// to produce a single object or a list of objects that can be used /// as sources for Avalon data bindings. /// It is a convenience wrapper around existing data model, it does not replace any data model. /// A data provider does not attempt to condense the complexity and versatility of a data model /// like ADO into one single object with a few properties. /// ////// DataSourceProvider is an abstract class and cannot directly be used as a data provider. /// Use one of the derived concrete provider, e.g. XmlDataProvider, ObjectDataProvider. /// The DataProvider aware of Avalon's threading and dispatcher model. The data provider assumes /// the thread at creation time to be the UI thread. Events will get marshalled from a worker thread /// to the app's UI thread. /// public abstract class DataSourceProvider : INotifyPropertyChanged, ISupportInitialize { ////// constructor captures the Dispatcher associated with the current thread /// protected DataSourceProvider() { _dispatcher = Dispatcher.CurrentDispatcher; } ////// Start the initial query to the underlying data model. /// The result will be returned on the Data property. /// This method is typically called by the binding engine when /// dependent data bindings are activated. /// Set IsInitialLoadEnabled = false to prevent or delay the automatic loading of data. /// ////// The InitialLoad method can be called multiple times. /// The provider is expected to ignore subsequent calls once the provider /// is busy executing the initial query, i.e. the provider shall not restart /// an already running query when InitialLoad is called again. /// When the query finishes successfully, any InitialLoad call will still not re-query data. /// The InitialLoad operation is typically asynchronous, a DataChanged event will /// be raised when the Data property assumed a new value. /// The application should call Refresh to cause a refresh of data. /// public void InitialLoad() { // ignore call if IsInitialLoadEnabled == false or already started initialization if (!IsInitialLoadEnabled || _initialLoadCalled) return; _initialLoadCalled = true; BeginQuery(); } ////// Initiates a Refresh Operation to the underlying data model. /// The result will be returned on the Data property. /// ////// A refresh operation is typically asynchronous, a DataChanged event will /// be raised when the Data property assumed a new value. /// If the refresh operation fails, the Data property will be set to null; /// the Error property will be set with the error exception. /// The app can call Refresh while a previous refresh is still underway. /// Calling Refresh twice will cause the DataChanged event to raise twice. /// public void Refresh() { _initialLoadCalled = true; BeginQuery(); } ////// Set IsInitialLoadEnabled = false to prevent or delay the automatic loading of data. /// [DefaultValue(true)] public bool IsInitialLoadEnabled { get { return _isInitialLoadEnabled; } set { _isInitialLoadEnabled = value; OnPropertyChanged(new PropertyChangedEventArgs("IsInitialLoadEnabled")); } } ////// Get the underlying data object. /// This is the resulting data source the data provider /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object Data { get { return _data; } } ////// Raise this event when a new data object becomes available /// on the Data property. /// public event EventHandler DataChanged; ////// Return the error of the last query operation. /// To indicate there was no error, it will return null /// public Exception Error { get { return _error; } } ////// Enter a Defer Cycle. /// Defer cycles are used to coalesce property changes, any automatic /// Refresh is delayed until the Defer Cycle is exited. /// ////// most typical usage is with a using block to set multiple proporties /// without the automatic Refresh to occur /// public virtual IDisposable DeferRefresh() { ++_deferLevel; return new DeferHelper(this); } #region ISupportInitialize ////// XmlDataProvider xdv = new XmlDataProvider(); /// using(xdv.DeferRefresh()) { /// xdv.Source = "http://foo.com/bar.xml"; /// xdv.XPath = "/Bla/Baz[@Boo='xyz']"; /// } ///
////// Initialization of this element is about to begin /// void ISupportInitialize.BeginInit() { BeginInit(); } ////// Initialization of this element has completed /// void ISupportInitialize.EndInit() { EndInit(); } #endregion ////// PropertyChanged event (per event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { add { PropertyChanged += value; } remove { PropertyChanged -= value; } } //----------------------------------------------------- // // Protected Properties // //----------------------------------------------------- ///). /// /// IsRefreshDeferred returns true if there is still an /// outstanding DeferRefresh in use. To get the best use /// out of refresh deferral, derived classes should try /// not to call Refresh when IsRefreshDeferred is true. /// protected bool IsRefreshDeferred { get { return ( (_deferLevel > 0) || (!IsInitialLoadEnabled && !_initialLoadCalled)); } } ////// The current Dispatcher to the Avalon UI thread to use. /// ////// By default, this is the Dispatcher associated with the thread /// on which this DataProvider instance was created. /// protected Dispatcher Dispatcher { get { return _dispatcher; } set { if (_dispatcher != value) { _dispatcher = value; } } } //------------------------------------------------------ // // Protected Methods // //----------------------------------------------------- #region Protected Methods ////// Overridden by concrete data provider class. /// the base class will call this method when InitialLoad or Refresh /// has been called and will delay this call if refresh is deferred ot /// initial load is disabled. /// ////// The implementor can choose to execute the query on the same thread or /// on a background thread or using asynchronous API. /// When the query is complete, call OnQueryFinished to have the public properties updated. /// protected virtual void BeginQuery() { } ////// A concrete data provider will call this method /// to indicate that a query has finished. /// ////// This callback can be called from any thread, this implementation /// will marshal back the result to the UI thread /// before setting any of the public properties and before raising any events. /// resulting data from query /// protected void OnQueryFinished(object newData) { OnQueryFinished(newData, null, null, null); } ////// A concrete data provider will call this method /// to indicate that a query has finished. /// ////// This callback can be called from any thread, this implementation /// will marshal back the result to the UI thread /// before setting any of the public properties and before raising any events. /// resulting data from query /// error that occured while running query; null signals no error /// optional delegate to execute completion work on UI thread, e.g. setting additional properties /// optional arguments to send as parameter with the completionWork delegate /// protected virtual void OnQueryFinished(object newData, Exception error, DispatcherOperationCallback completionWork, object callbackArguments) { Invariant.Assert(Dispatcher != null); // check if we're already on the dispatcher thread if (Dispatcher.CheckAccess()) { // already on UI thread UpdateWithNewResult(error, newData, completionWork, callbackArguments); } else { // marshal the result back to the main thread Dispatcher.BeginInvoke( DispatcherPriority.Normal, UpdateWithNewResultCallback, new object[] { this, error, newData, completionWork, callbackArguments }); } } ////// PropertyChanged event (per protected virtual event PropertyChangedEventHandler PropertyChanged; ///). /// /// Raises a PropertyChanged event (per protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, e); } } ///). /// /// Initialization of this element is about to begin; /// no implicit Refresh occurs until the matched EndInit is called /// protected virtual void BeginInit() { ++_deferLevel; } ////// Initialization of this element has completed; /// this causes a Refresh if no other deferred refresh is outstanding /// protected virtual void EndInit() { EndDefer(); } #endregion Protected Methods //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods private void EndDefer() { Debug.Assert(_deferLevel > 0); --_deferLevel; if (_deferLevel == 0) { Refresh(); } } private static object UpdateWithNewResult(object arg) { object[] args = (object[]) arg; Invariant.Assert(args.Length == 5); DataSourceProvider provider = (DataSourceProvider) args[0]; Exception error = (Exception) args[1]; object newData = args[2]; DispatcherOperationCallback completionWork = (DispatcherOperationCallback) args[3]; object callbackArgs = args[4]; provider.UpdateWithNewResult(error, newData, completionWork, callbackArgs); return null; } private void UpdateWithNewResult(Exception error, object newData, DispatcherOperationCallback completionWork, object callbackArgs) { bool errorChanged = (_error != error); _error = error; if (error != null) { newData = null; _initialLoadCalled = false; // allow again InitialLoad after an error } _data = newData; if (completionWork != null) completionWork(callbackArgs); // notify any listeners if (DataChanged != null) { DataChanged(this, EventArgs.Empty); } if (errorChanged) OnPropertyChanged(new PropertyChangedEventArgs("Error")); } #endregion Private Methods //----------------------------------------------------- // // Private Types // //------------------------------------------------------ #region Private Types private class DeferHelper : IDisposable { public DeferHelper(DataSourceProvider provider) { _provider = provider; } public void Dispose() { if (_provider != null) { _provider.EndDefer(); _provider = null; } } private DataSourceProvider _provider; } #endregion //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- private bool _isInitialLoadEnabled = true; private bool _initialLoadCalled; private int _deferLevel; private object _data; private Exception _error; private Dispatcher _dispatcher; static readonly DispatcherOperationCallback UpdateWithNewResultCallback = new DispatcherOperationCallback(UpdateWithNewResult); } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: common base class and contract for data source provider objects // // Specs: http://avalon/connecteddata/Specs/Avalon%20DataProviders.mht // //--------------------------------------------------------------------------- using System; using System.Diagnostics; using System.ComponentModel; using System.Threading; using System.Windows.Threading; // Dispatcher* using MS.Internal; // Invariant namespace System.Windows.Data { ////// Common base class and contract for data source providers. /// A DataProvider in Avalon is the factory that executes some query /// to produce a single object or a list of objects that can be used /// as sources for Avalon data bindings. /// It is a convenience wrapper around existing data model, it does not replace any data model. /// A data provider does not attempt to condense the complexity and versatility of a data model /// like ADO into one single object with a few properties. /// ////// DataSourceProvider is an abstract class and cannot directly be used as a data provider. /// Use one of the derived concrete provider, e.g. XmlDataProvider, ObjectDataProvider. /// The DataProvider aware of Avalon's threading and dispatcher model. The data provider assumes /// the thread at creation time to be the UI thread. Events will get marshalled from a worker thread /// to the app's UI thread. /// public abstract class DataSourceProvider : INotifyPropertyChanged, ISupportInitialize { ////// constructor captures the Dispatcher associated with the current thread /// protected DataSourceProvider() { _dispatcher = Dispatcher.CurrentDispatcher; } ////// Start the initial query to the underlying data model. /// The result will be returned on the Data property. /// This method is typically called by the binding engine when /// dependent data bindings are activated. /// Set IsInitialLoadEnabled = false to prevent or delay the automatic loading of data. /// ////// The InitialLoad method can be called multiple times. /// The provider is expected to ignore subsequent calls once the provider /// is busy executing the initial query, i.e. the provider shall not restart /// an already running query when InitialLoad is called again. /// When the query finishes successfully, any InitialLoad call will still not re-query data. /// The InitialLoad operation is typically asynchronous, a DataChanged event will /// be raised when the Data property assumed a new value. /// The application should call Refresh to cause a refresh of data. /// public void InitialLoad() { // ignore call if IsInitialLoadEnabled == false or already started initialization if (!IsInitialLoadEnabled || _initialLoadCalled) return; _initialLoadCalled = true; BeginQuery(); } ////// Initiates a Refresh Operation to the underlying data model. /// The result will be returned on the Data property. /// ////// A refresh operation is typically asynchronous, a DataChanged event will /// be raised when the Data property assumed a new value. /// If the refresh operation fails, the Data property will be set to null; /// the Error property will be set with the error exception. /// The app can call Refresh while a previous refresh is still underway. /// Calling Refresh twice will cause the DataChanged event to raise twice. /// public void Refresh() { _initialLoadCalled = true; BeginQuery(); } ////// Set IsInitialLoadEnabled = false to prevent or delay the automatic loading of data. /// [DefaultValue(true)] public bool IsInitialLoadEnabled { get { return _isInitialLoadEnabled; } set { _isInitialLoadEnabled = value; OnPropertyChanged(new PropertyChangedEventArgs("IsInitialLoadEnabled")); } } ////// Get the underlying data object. /// This is the resulting data source the data provider /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object Data { get { return _data; } } ////// Raise this event when a new data object becomes available /// on the Data property. /// public event EventHandler DataChanged; ////// Return the error of the last query operation. /// To indicate there was no error, it will return null /// public Exception Error { get { return _error; } } ////// Enter a Defer Cycle. /// Defer cycles are used to coalesce property changes, any automatic /// Refresh is delayed until the Defer Cycle is exited. /// ////// most typical usage is with a using block to set multiple proporties /// without the automatic Refresh to occur /// public virtual IDisposable DeferRefresh() { ++_deferLevel; return new DeferHelper(this); } #region ISupportInitialize ////// XmlDataProvider xdv = new XmlDataProvider(); /// using(xdv.DeferRefresh()) { /// xdv.Source = "http://foo.com/bar.xml"; /// xdv.XPath = "/Bla/Baz[@Boo='xyz']"; /// } ///
////// Initialization of this element is about to begin /// void ISupportInitialize.BeginInit() { BeginInit(); } ////// Initialization of this element has completed /// void ISupportInitialize.EndInit() { EndInit(); } #endregion ////// PropertyChanged event (per event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { add { PropertyChanged += value; } remove { PropertyChanged -= value; } } //----------------------------------------------------- // // Protected Properties // //----------------------------------------------------- ///). /// /// IsRefreshDeferred returns true if there is still an /// outstanding DeferRefresh in use. To get the best use /// out of refresh deferral, derived classes should try /// not to call Refresh when IsRefreshDeferred is true. /// protected bool IsRefreshDeferred { get { return ( (_deferLevel > 0) || (!IsInitialLoadEnabled && !_initialLoadCalled)); } } ////// The current Dispatcher to the Avalon UI thread to use. /// ////// By default, this is the Dispatcher associated with the thread /// on which this DataProvider instance was created. /// protected Dispatcher Dispatcher { get { return _dispatcher; } set { if (_dispatcher != value) { _dispatcher = value; } } } //------------------------------------------------------ // // Protected Methods // //----------------------------------------------------- #region Protected Methods ////// Overridden by concrete data provider class. /// the base class will call this method when InitialLoad or Refresh /// has been called and will delay this call if refresh is deferred ot /// initial load is disabled. /// ////// The implementor can choose to execute the query on the same thread or /// on a background thread or using asynchronous API. /// When the query is complete, call OnQueryFinished to have the public properties updated. /// protected virtual void BeginQuery() { } ////// A concrete data provider will call this method /// to indicate that a query has finished. /// ////// This callback can be called from any thread, this implementation /// will marshal back the result to the UI thread /// before setting any of the public properties and before raising any events. /// resulting data from query /// protected void OnQueryFinished(object newData) { OnQueryFinished(newData, null, null, null); } ////// A concrete data provider will call this method /// to indicate that a query has finished. /// ////// This callback can be called from any thread, this implementation /// will marshal back the result to the UI thread /// before setting any of the public properties and before raising any events. /// resulting data from query /// error that occured while running query; null signals no error /// optional delegate to execute completion work on UI thread, e.g. setting additional properties /// optional arguments to send as parameter with the completionWork delegate /// protected virtual void OnQueryFinished(object newData, Exception error, DispatcherOperationCallback completionWork, object callbackArguments) { Invariant.Assert(Dispatcher != null); // check if we're already on the dispatcher thread if (Dispatcher.CheckAccess()) { // already on UI thread UpdateWithNewResult(error, newData, completionWork, callbackArguments); } else { // marshal the result back to the main thread Dispatcher.BeginInvoke( DispatcherPriority.Normal, UpdateWithNewResultCallback, new object[] { this, error, newData, completionWork, callbackArguments }); } } ////// PropertyChanged event (per protected virtual event PropertyChangedEventHandler PropertyChanged; ///). /// /// Raises a PropertyChanged event (per protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, e); } } ///). /// /// Initialization of this element is about to begin; /// no implicit Refresh occurs until the matched EndInit is called /// protected virtual void BeginInit() { ++_deferLevel; } ////// Initialization of this element has completed; /// this causes a Refresh if no other deferred refresh is outstanding /// protected virtual void EndInit() { EndDefer(); } #endregion Protected Methods //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods private void EndDefer() { Debug.Assert(_deferLevel > 0); --_deferLevel; if (_deferLevel == 0) { Refresh(); } } private static object UpdateWithNewResult(object arg) { object[] args = (object[]) arg; Invariant.Assert(args.Length == 5); DataSourceProvider provider = (DataSourceProvider) args[0]; Exception error = (Exception) args[1]; object newData = args[2]; DispatcherOperationCallback completionWork = (DispatcherOperationCallback) args[3]; object callbackArgs = args[4]; provider.UpdateWithNewResult(error, newData, completionWork, callbackArgs); return null; } private void UpdateWithNewResult(Exception error, object newData, DispatcherOperationCallback completionWork, object callbackArgs) { bool errorChanged = (_error != error); _error = error; if (error != null) { newData = null; _initialLoadCalled = false; // allow again InitialLoad after an error } _data = newData; if (completionWork != null) completionWork(callbackArgs); // notify any listeners if (DataChanged != null) { DataChanged(this, EventArgs.Empty); } if (errorChanged) OnPropertyChanged(new PropertyChangedEventArgs("Error")); } #endregion Private Methods //----------------------------------------------------- // // Private Types // //------------------------------------------------------ #region Private Types private class DeferHelper : IDisposable { public DeferHelper(DataSourceProvider provider) { _provider = provider; } public void Dispose() { if (_provider != null) { _provider.EndDefer(); _provider = null; } } private DataSourceProvider _provider; } #endregion //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- private bool _isInitialLoadEnabled = true; private bool _initialLoadCalled; private int _deferLevel; private object _data; private Exception _error; private Dispatcher _dispatcher; static readonly DispatcherOperationCallback UpdateWithNewResultCallback = new DispatcherOperationCallback(UpdateWithNewResult); } } // 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
- TextEmbeddedObject.cs
- UriTemplatePathPartiallyEquivalentSet.cs
- WaitingCursor.cs
- WebPartDisplayMode.cs
- ReceiveMessageAndVerifySecurityAsyncResultBase.cs
- COM2IProvidePropertyBuilderHandler.cs
- COM2ComponentEditor.cs
- TextRangeEdit.cs
- LinkedList.cs
- JoinSymbol.cs
- SystemPens.cs
- XPathNodeInfoAtom.cs
- SignedXml.cs
- Ops.cs
- GACIdentityPermission.cs
- WizardStepBase.cs
- SynchronousChannel.cs
- Model3DGroup.cs
- ScriptingAuthenticationServiceSection.cs
- ReplyChannelBinder.cs
- TextViewBase.cs
- SharedUtils.cs
- Calendar.cs
- ParallelTimeline.cs
- OletxResourceManager.cs
- EnumerableCollectionView.cs
- ComboBox.cs
- XmlReader.cs
- EncryptedPackageFilter.cs
- TryCatch.cs
- HelloMessage11.cs
- TaskResultSetter.cs
- XamlReaderHelper.cs
- SingleAnimation.cs
- ObjectItemAssemblyLoader.cs
- DisplayNameAttribute.cs
- HttpListenerTimeoutManager.cs
- VisualCollection.cs
- EventArgs.cs
- XDeferredAxisSource.cs
- ThreadStartException.cs
- InstalledFontCollection.cs
- LockCookie.cs
- SqlTransaction.cs
- StopStoryboard.cs
- validationstate.cs
- WindowInteractionStateTracker.cs
- MappingModelBuildProvider.cs
- IIS7WorkerRequest.cs
- ExpressionVisitor.cs
- AnnotationHighlightLayer.cs
- WebPartChrome.cs
- Debug.cs
- TTSEngineTypes.cs
- RawKeyboardInputReport.cs
- HtmlTextArea.cs
- FormatSettings.cs
- HwndProxyElementProvider.cs
- Type.cs
- ContentTextAutomationPeer.cs
- NavigationHelper.cs
- EmptyEnumerator.cs
- ApplicationFileParser.cs
- ValueHandle.cs
- QueueAccessMode.cs
- UserControl.cs
- GeometryDrawing.cs
- QilBinary.cs
- PointHitTestParameters.cs
- ItemAutomationPeer.cs
- CssStyleCollection.cs
- DrawingAttributesDefaultValueFactory.cs
- MultiSelectRootGridEntry.cs
- BitArray.cs
- SqlDependency.cs
- Ray3DHitTestResult.cs
- SmiEventSink_Default.cs
- EntityConnectionStringBuilder.cs
- HtmlTernaryTree.cs
- ResourcesChangeInfo.cs
- BuildProviderCollection.cs
- WebBrowserNavigatedEventHandler.cs
- RecordManager.cs
- PackageRelationshipCollection.cs
- ManagedIStream.cs
- DesignerSerializationOptionsAttribute.cs
- ApplicationId.cs
- BamlMapTable.cs
- QilReference.cs
- ElementNotEnabledException.cs
- SqlParameterCollection.cs
- DbgCompiler.cs
- FileUtil.cs
- AnimationClock.cs
- ObjRef.cs
- WmfPlaceableFileHeader.cs
- WebControlToolBoxItem.cs
- ContextMenu.cs
- UnmanagedBitmapWrapper.cs
- XmlObjectSerializerReadContext.cs