Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / Windows / Data / DataSourceProvider.cs / 1305600 / 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 OnPropertyChanged(new PropertyChangedEventArgs("Data")); 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() { GC.SuppressFinalize(this); 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
- SmiMetaData.cs
- TypeReference.cs
- UIElementCollection.cs
- DrawTreeNodeEventArgs.cs
- EntitySetBaseCollection.cs
- SectionInformation.cs
- BuilderPropertyEntry.cs
- DesignerActionKeyboardBehavior.cs
- ColorConvertedBitmap.cs
- SmtpNegotiateAuthenticationModule.cs
- MaterialCollection.cs
- TextFormatterImp.cs
- RecordsAffectedEventArgs.cs
- StorageInfo.cs
- CompoundFileStorageReference.cs
- Exceptions.cs
- DiscreteKeyFrames.cs
- DebuggerAttributes.cs
- ScalarConstant.cs
- ToolBarButton.cs
- CustomWebEventKey.cs
- TextHintingModeValidation.cs
- CharKeyFrameCollection.cs
- ColorConvertedBitmapExtension.cs
- CommonXSendMessage.cs
- UnionExpr.cs
- TextEditorLists.cs
- EventNotify.cs
- DbFunctionCommandTree.cs
- DesignTimeParseData.cs
- ManifestSignatureInformation.cs
- ToolStripContentPanel.cs
- InkSerializer.cs
- HtmlInputSubmit.cs
- Resources.Designer.cs
- WindowsGraphics2.cs
- ListViewDesigner.cs
- GenericQueueSurrogate.cs
- DataControlImageButton.cs
- QueryableDataSource.cs
- FieldMetadata.cs
- OrderByQueryOptionExpression.cs
- SwitchCase.cs
- TdsParserSafeHandles.cs
- AppSettingsSection.cs
- Dictionary.cs
- ApplicationSecurityManager.cs
- SqlDataSourceQueryEditorForm.cs
- TailCallAnalyzer.cs
- ListCollectionView.cs
- CallSiteBinder.cs
- ConfigsHelper.cs
- IssuedSecurityTokenProvider.cs
- CqlParserHelpers.cs
- smtppermission.cs
- QueryOptionExpression.cs
- XPathDocument.cs
- TypeReference.cs
- __Filters.cs
- BitmapScalingModeValidation.cs
- SqlConnectionPoolGroupProviderInfo.cs
- SerializableAttribute.cs
- ApplicationHost.cs
- ZoomPercentageConverter.cs
- StoreUtilities.cs
- IndexingContentUnit.cs
- WebFaultClientMessageInspector.cs
- ElementProxy.cs
- SettingsProviderCollection.cs
- UnsafeNativeMethods.cs
- WindowsPrincipal.cs
- COAUTHINFO.cs
- DataGridColumnsPage.cs
- CompositeCollection.cs
- Win32.cs
- EdmFunction.cs
- PeerNameResolver.cs
- ManualResetEvent.cs
- HostVisual.cs
- TextFormatterImp.cs
- TabItem.cs
- TimeSpanMinutesConverter.cs
- CapabilitiesPattern.cs
- DocumentPaginator.cs
- GroupBoxDesigner.cs
- EntityContainerEmitter.cs
- GraphicsContext.cs
- GC.cs
- CaseStatement.cs
- Roles.cs
- followingsibling.cs
- Int16AnimationBase.cs
- ListItemViewControl.cs
- ReferencedType.cs
- NoClickablePointException.cs
- TimeStampChecker.cs
- AdornerDecorator.cs
- SqlTransaction.cs
- TraceProvider.cs
- PrinterUnitConvert.cs