Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / 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
- RowVisual.cs
- NotifyInputEventArgs.cs
- EditingCommands.cs
- DeleteWorkflowOwnerCommand.cs
- BinarySecretSecurityToken.cs
- AppearanceEditorPart.cs
- COM2IProvidePropertyBuilderHandler.cs
- CompositionTarget.cs
- StringToken.cs
- UncommonField.cs
- DrawingContextWalker.cs
- Int32Storage.cs
- DrawingImage.cs
- SecurityVerifiedMessage.cs
- HandoffBehavior.cs
- PnrpPermission.cs
- DesignerToolboxInfo.cs
- CoTaskMemSafeHandle.cs
- InputProcessorProfiles.cs
- DataRow.cs
- AuthenticateEventArgs.cs
- SQLDecimal.cs
- DescendantBaseQuery.cs
- WindowsFormsSynchronizationContext.cs
- TrustLevelCollection.cs
- ProcessHostFactoryHelper.cs
- TextParagraph.cs
- Transform3DCollection.cs
- TableCell.cs
- ControlAdapter.cs
- TextLineBreak.cs
- SqlMethodTransformer.cs
- MultiPartWriter.cs
- AsyncCompletedEventArgs.cs
- EditorBrowsableAttribute.cs
- EllipticalNodeOperations.cs
- TextParagraph.cs
- XsltLoader.cs
- EtwProvider.cs
- HintTextMaxWidthConverter.cs
- WeakEventManager.cs
- FixedSOMTableRow.cs
- EnvironmentPermission.cs
- ReadOnlyCollection.cs
- ModuleElement.cs
- TextPattern.cs
- MgmtResManager.cs
- HebrewNumber.cs
- CaseInsensitiveHashCodeProvider.cs
- StickyNoteAnnotations.cs
- ByteConverter.cs
- KeyValueConfigurationCollection.cs
- ScriptRegistrationManager.cs
- ValidationError.cs
- RichTextBoxDesigner.cs
- AutoResetEvent.cs
- AttachInfo.cs
- BCLDebug.cs
- CompilerGeneratedAttribute.cs
- WindowsSecurityTokenAuthenticator.cs
- SectionRecord.cs
- OleDragDropHandler.cs
- PropertyEmitterBase.cs
- SecurityManager.cs
- WebBaseEventKeyComparer.cs
- ColorTransform.cs
- FormatterServices.cs
- HttpProcessUtility.cs
- ThreadExceptionEvent.cs
- CaretElement.cs
- MDIWindowDialog.cs
- FragmentQuery.cs
- PolicyValidationException.cs
- SchemaAttDef.cs
- Debugger.cs
- PageSettings.cs
- MultiView.cs
- QueueProcessor.cs
- MSAANativeProvider.cs
- ModelPropertyDescriptor.cs
- TextRangeSerialization.cs
- FixedTextSelectionProcessor.cs
- DataControlImageButton.cs
- GroupByQueryOperator.cs
- ParseChildrenAsPropertiesAttribute.cs
- IdleTimeoutMonitor.cs
- WebColorConverter.cs
- MarkerProperties.cs
- MimeTypeAttribute.cs
- MultiBinding.cs
- PrintDocument.cs
- DataServiceHost.cs
- TypeExtensions.cs
- WebPart.cs
- DecimalAverageAggregationOperator.cs
- XPathScanner.cs
- DBBindings.cs
- WebPartTracker.cs
- RecordBuilder.cs
- WindowsImpersonationContext.cs