Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / 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: [....]/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
///
/// XmlDataProvider xdv = new XmlDataProvider();
/// using(xdv.DeferRefresh()) {
/// xdv.Source = "http://foo.com/bar.xml";
/// xdv.XPath = "/Bla/Baz[@Boo='xyz']";
/// }
///
///
public virtual IDisposable DeferRefresh()
{
++_deferLevel;
return new DeferHelper(this);
}
#region ISupportInitialize
///
/// 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
- XslNumber.cs
- RegexCapture.cs
- CoTaskMemHandle.cs
- InfoCardTraceRecord.cs
- ProcessModelInfo.cs
- ChannelSinkStacks.cs
- PackagePartCollection.cs
- DataBindingCollectionConverter.cs
- ExpressionPrefixAttribute.cs
- FontStyle.cs
- HttpServerVarsCollection.cs
- XmlRawWriterWrapper.cs
- SchemaType.cs
- ExpressionNode.cs
- NamespaceInfo.cs
- Int16Storage.cs
- CertificateManager.cs
- TemplateEditingService.cs
- AddressAlreadyInUseException.cs
- DataPointer.cs
- GlyphTypeface.cs
- CategoryValueConverter.cs
- TerminateDesigner.cs
- XhtmlBasicValidatorAdapter.cs
- ContextConfiguration.cs
- PageVisual.cs
- ToolboxItem.cs
- MessagePartDescription.cs
- TemplateBindingExtension.cs
- Point4DConverter.cs
- ToolStripMenuItemDesigner.cs
- OdbcConnectionHandle.cs
- FactoryRecord.cs
- DisplayNameAttribute.cs
- IisTraceListener.cs
- ProfileWorkflowElement.cs
- DecimalStorage.cs
- ArgIterator.cs
- Literal.cs
- PropertyValue.cs
- DataViewManagerListItemTypeDescriptor.cs
- UnsafeNativeMethods.cs
- WebResourceAttribute.cs
- TextEndOfSegment.cs
- CustomErrorCollection.cs
- XPathAxisIterator.cs
- Volatile.cs
- EmbeddedObject.cs
- WebPartEditorOkVerb.cs
- DataGridViewRowErrorTextNeededEventArgs.cs
- CheckBox.cs
- ValidatorCollection.cs
- XhtmlCssHandler.cs
- InheritanceAttribute.cs
- XsltException.cs
- safesecurityhelperavalon.cs
- RootBrowserWindow.cs
- EventLogEntryCollection.cs
- ByteKeyFrameCollection.cs
- ContractListAdapter.cs
- HttpWriter.cs
- SpAudioStreamWrapper.cs
- ViewManagerAttribute.cs
- ReflectionTypeLoadException.cs
- UriSection.cs
- FlowDocument.cs
- DashStyle.cs
- NullReferenceException.cs
- CqlGenerator.cs
- DataSourceView.cs
- DataContractJsonSerializer.cs
- XmlSchemaGroupRef.cs
- ColumnCollection.cs
- ToolStripMenuItem.cs
- SamlConstants.cs
- BoundConstants.cs
- NumericUpDown.cs
- CompositeScriptReference.cs
- SerializeAbsoluteContext.cs
- ConnectionInterfaceCollection.cs
- StaticSiteMapProvider.cs
- safelink.cs
- WindowCollection.cs
- LicFileLicenseProvider.cs
- BrowserDefinitionCollection.cs
- HwndPanningFeedback.cs
- ElementsClipboardData.cs
- DEREncoding.cs
- CounterSampleCalculator.cs
- MdiWindowListStrip.cs
- LabelAutomationPeer.cs
- IPCCacheManager.cs
- SiteMapProvider.cs
- KernelTypeValidation.cs
- BStrWrapper.cs
- HttpResponse.cs
- RadioButton.cs
- SQLGuid.cs
- DataGridViewRowsAddedEventArgs.cs
- ProviderSettings.cs