XmlDataProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Data / XmlDataProvider.cs / 1305600 / XmlDataProvider.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Implementation of XmlDataProvider object. 
// 
// Specs:       http://avalon/connecteddata/Specs/Avalon%20DataProviders.mht
//              http://avalon/connecteddata/Specs/XmlDataSource.mht 
//
//---------------------------------------------------------------------------

using System; 
using System.IO;                    // Stream
using System.Collections; 
using System.ComponentModel;        // ISupportInitialize, AsyncCompletedEventHandler, [DesignerSerialization*], [DefaultValue] 
using System.Diagnostics;
using System.IO.Packaging;          // PackUriHelper 
using System.Globalization;         // CultureInfo
using System.Net;                   // WebRequest, IWebRequestCreate
using System.Threading;             // ThreadPool, WaitCallback
using System.Xml; 
using System.Xml.Schema;
using System.Xml.Serialization;     // IXmlSerializable 
using System.Xml.XPath; 
using System.Windows;
using System.Windows.Data; 
using System.Windows.Threading;     // Dispatcher*
using System.Windows.Markup; // IUriContext, [XamlDesignerSerializer]
using MS.Internal;                  // CriticalExceptions
using MS.Internal.Utility;          // BindUriHelper 
using MS.Internal.Data;             // XmlDataCollection
 
namespace System.Windows.Data 
{
    ///  
    /// XmlDataProvider class, gets XmlNodes to use as source in data binding
    /// 
    /// 
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] 
    [ContentProperty("XmlSerializer")]
    public class XmlDataProvider : DataSourceProvider, IUriContext 
    { 
        //-----------------------------------------------------
        // 
        //  Constructors
        //
        //-----------------------------------------------------
 
        /// 
        /// Instantiates a new instance of a XmlDataProvider 
        ///  
        public XmlDataProvider()
        { 
        }

        //------------------------------------------------------
        // 
        //  Public Properties
        // 
        //----------------------------------------------------- 

        #region Public Properties 

        /// 
        /// Source property, indicated the Uri of the source Xml data file, if this
        /// property is set, then any inline xml data is discarded. 
        /// 
        ///  
        /// Setting this property will implicitly cause this DataProvider to refresh. 
        /// When changing multiple refresh-causing properties, the use of
        ///  is recommended. 
        /// 
        public Uri Source
        {
            get { return _source; } 
            set
            { 
                if ((_domSetDocument != null) || _source != value) 
                {
                    _domSetDocument = null; 
                    _source = value;

                    OnPropertyChanged(new PropertyChangedEventArgs("Source"));
 
                    if (!IsRefreshDeferred)
                        Refresh(); 
                } 
            }
        } 

        /// 
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeSource() 
        {
            return (_domSetDocument == null) && (_source != null); 
        }

        /// 
        /// Document Property, returns the current XmlDocument that this data source 
        /// is using, if set the Source property is cleared and any inline xml data is
        /// discarded 
        ///  
        /// 
        /// Setting this property will implicitly cause this DataProvider to refresh. 
        /// When changing multiple refresh-causing properties, the use of
        ///  is recommended.
        /// 
        // this property cannot be serialized since the produced XAML/XML wouldn't be parseable anymore; 
        // instead, a user-set DOM is serialized as InlineData
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public XmlDocument Document 
        {
            get { return _document; } 
            set
            {
                if ((_domSetDocument == null) || _source != null || _document != value)
                { 
                    _domSetDocument = value;
 
                    _source = null; 
                    OnPropertyChanged(new PropertyChangedEventArgs("Source"));
 
                    ChangeDocument(value); // set immediately so that next get_Document returns this value,
                                       // even when data provider is in deferred or asynch mode

                    if (!IsRefreshDeferred) 
                        Refresh();
                } 
            } 
        }
 
        /// 
        /// XPath property, the XPath query used for generating the DataCollection
        /// 
        ///  
        /// Setting this property will implicitly cause this DataProvider to refresh.
        /// When changing multiple refresh-causing properties, the use of 
        ///  is recommended. 
        /// 
        [DesignerSerializationOptions(DesignerSerializationOptions.SerializeAsAttribute)] 
        public string XPath
        {
            get { return _xPath; }
            set 
            {
                if (_xPath != value) 
                { 
                    _xPath = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("XPath")); 

                    if (!IsRefreshDeferred)
                        Refresh();
                } 
            }
        } 
 
        /// 
        /// This method is used by TypeDescriptor to determine if this property should 
        /// be serialized.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeXPath() 
        {
            return (_xPath != null) && (_xPath.Length != 0); 
        } 

        ///  
        /// XmlNamespaceManager property, XmlNamespaceManager used for executing XPath queries.
        /// in order to set this property using markup, an XmlDataNamespaceManager resource can be used.
        /// 
        ///  
        /// Setting this property will implicitly cause this DataProvider to refresh.
        /// When changing multiple refresh-causing properties, the use of 
        ///  is recommended. 
        /// 
        [DefaultValue(null)] 
        public XmlNamespaceManager XmlNamespaceManager
        {
            get { return _nsMgr; }
            set 
            {
                if (_nsMgr != value) 
                { 
                    _nsMgr = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("XmlNamespaceManager")); 

                    if (!IsRefreshDeferred)
                        Refresh();
                } 
            }
        } 
 
        /// 
        /// If true object creation will be performed in a worker 
        /// thread, otherwise will be done in active context.
        /// 
        [DefaultValue(true)]
        public bool IsAsynchronous 
        {
            get { return _isAsynchronous; } 
            set { _isAsynchronous = value; } 
        }
 
        /// 
        /// The content property for inline Xml data.
        /// Used by the parser to compile the literal content of the embedded XML island.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public IXmlSerializable XmlSerializer 
        {
            get 
            {
                if (_xmlSerializer == null)
                {
                    _xmlSerializer = new XmlIslandSerializer(this); 
                }
                return _xmlSerializer; 
            } 
        }
 
        /// 
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeXmlSerializer() 
        { 
            // serialize InlineData only if the Xml DOM used was originally a inline Xml data island
            return (DocumentForSerialization != null); 
        }

        #endregion
 

        #region IUriContext 
 
        /// 
        ///     Provides the base uri of the current context. 
        /// 
        Uri IUriContext.BaseUri
        {
            get { return BaseUri; } 
            set { BaseUri = value; }
        } 
 
        /// 
        ///     Implementation for BaseUri. 
        /// 
        protected virtual Uri BaseUri
        {
            get { return _baseUri; } 
            set { _baseUri = value; }
        } 
 
        #endregion IUriContext
 
        //------------------------------------------------------
        //
        //  Protected Methods
        // 
        //------------------------------------------------------
 
        ///  
        /// Prepare loading either the external XML or inline XML and
        /// produce Xml node collection. 
        /// Execution is 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 (_source != null)
            { 
                // load DOM from external source 
                Debug.Assert(_domSetDocument == null, "Should not be possible to be using Source and user-set Doc at the same time.");
                DiscardInline(); 
                LoadFromSource(); // will execute synch or asycnh, depends on IsAsynchronous
            }
            else
            { 
                XmlDocument doc = null;
                if (_domSetDocument != null) 
                { 
                    DiscardInline();
                    doc = _domSetDocument; 
                }
                else // inline doc
                {
                    // Did we already parse the inline DOM? 
                    // Don't do this during EndInit - it duplicates effort of Parse
                    if (_inEndInit) 
                        return; 

                    doc = _savedDocument; 
                }

                // Doesn't matter if the doc is set programmatically or from inline,
                // here we create a new collection for it and make it active. 
                if (IsAsynchronous && doc != null)
                { 
                    // process node collection on a worker thread ? 
                    ThreadPool.QueueUserWorkItem(new WaitCallback(BuildNodeCollectionAsynch),
                                                 doc); 
                }
                else if (doc != null || Data != null)
                {
                    // process the doc synchronously if we're in synchronous mode, 
                    // or if the doc is empty.  But don't process an empty doc
                    // if the data is already null, to avoid unnecessary work 
                    BuildNodeCollection(doc); 
                }
            } 
        }


        ///  
        ///     Initialization of this element has completed;
        ///     this causes a Refresh if no other deferred refresh is outstanding 
        ///  
        protected override void EndInit()
        { 
            // inhibit re-parsing of inline doc (from BeginQuery)
            try
            {
                _inEndInit = true; 
                base.EndInit();
            } 
            finally 
            {
                _inEndInit = false; 
            }
        }

 
        //-----------------------------------------------------
        // 
        //  Private Methods 
        //
        //------------------------------------------------------ 

        #region Preparing DOM

        // Load XML from a URI; this runs on caller thread of BeginQuery (Refresh/InitialLoad) 
        private void LoadFromSource()
        { 
            // convert the Source into an absolute URI 
            Uri sourceUri = this.Source;
            if (sourceUri.IsAbsoluteUri == false) 
            {
                Uri baseUri = (_baseUri != null) ? _baseUri : BindUriHelper.BaseUri;
                sourceUri = BindUriHelper.GetResolvedUri(baseUri, sourceUri);
            } 

            // create a request to load the content 
            // Ideally we would want to use RegisterPrefix and WebRequest.Create. 
            // However, these two functions regress 700k working set in System.dll and System.xml.dll
            //  which is mostly for logging and config. 
            // Call PackWebRequestFactory.CreateWebRequest to bypass the regression if possible
            //  by calling Create on PackWebRequest if uri is pack scheme
            WebRequest request = PackWebRequestFactory.CreateWebRequest(sourceUri);
 
            if (request == null)
            { 
                throw new Exception(SR.Get(SRID.WebRequestCreationFailed)); 
            }
 
            // load it on a worker thread ?
            if (IsAsynchronous)
                ThreadPool.QueueUserWorkItem(new WaitCallback(CreateDocFromExternalSourceAsynch),
                                             request); 
            else
                CreateDocFromExternalSource(request); 
 
        }
 
        #region Content Parsing implementation

        private class XmlIslandSerializer : IXmlSerializable
        { 
            internal XmlIslandSerializer(XmlDataProvider host)
            { 
                _host = host; 
            }
            public XmlSchema GetSchema() 
            {
                //
                return null;
            } 

            public void WriteXml(XmlWriter writer) 
            { 
                XmlDocument doc = _host.DocumentForSerialization;
                if (doc != null) 
                    doc.Save(writer);
            }

            public void ReadXml(XmlReader reader) 
            {
                _host.ParseInline(reader); 
            } 

            private XmlDataProvider _host; 
        }

        /// 
        /// Parse method, 
        /// 
        ///  
        private void ParseInline(XmlReader xmlReader) 
        {
            if ((_source == null) && (_domSetDocument == null) && _tryInlineDoc) 
            {
                // load it on a worker thread ?
                if (IsAsynchronous)
                { 
                    _waitForInlineDoc = new ManualResetEvent(false); // tells serializer to wait until _document is ready
                    ThreadPool.QueueUserWorkItem(new WaitCallback(CreateDocFromInlineXmlAsync), 
                                                     xmlReader); 
                }
                else 
                    CreateDocFromInlineXml(xmlReader);
            }
        }
 
        private XmlDocument DocumentForSerialization
        { 
            get 
            {
                // allow inline serialization only if the original XML data was inline 
                // or the user has assigned own DOM to our Document property
                if (_tryInlineDoc || (_savedDocument != null) || (_domSetDocument != null))
                {
                    // if inline or assigned doc hasn't been parsed yet, wait for it 
                    if (_waitForInlineDoc != null)
                        _waitForInlineDoc.WaitOne(); 
                    return _document; 
                }
                return null; 
            }
        }

        #endregion //Content Parsing implementation 

        // this method can run on a worker thread! 
        private void CreateDocFromInlineXmlAsync(object arg) 
        {
            XmlReader xmlReader = (XmlReader) arg; 
            CreateDocFromInlineXml(xmlReader);
        }

        // this method can run on a worker thread! 
        private void CreateDocFromInlineXml(XmlReader xmlReader)
        { 
            // Maybe things have changed and we don't want to use inline doc anymore 
            if (!_tryInlineDoc)
            { 
                _savedDocument = null;
                if (_waitForInlineDoc != null)
                    _waitForInlineDoc.Set();
                return; 
            }
 
            XmlDocument doc; 
            Exception ex = null;
 
            try
            {
                doc = new XmlDocument();
                try 
                {
                    if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.XmlProvider)) 
                    { 
                        TraceData.Trace(TraceEventType.Warning,
                                            TraceData.XmlLoadInline( 
                                                TraceData.Identify(this),
                                                Dispatcher.CheckAccess() ? "synchronous" : "asynchronous"));
                    }
 
                    // Load the inline doc from the reader
                    doc.Load(xmlReader); 
                } 
                catch (XmlException xmle)
                { 
                    if (TraceData.IsEnabled)
                        TraceData.Trace(TraceEventType.Error, TraceData.XmlDPInlineDocError, xmle);
                    ex = xmle;
                } 

                if (ex == null) 
                { 
                    // Save a copy of the inline document to be used in future
                    // queries, and by serialization. 
                    _savedDocument = (XmlDocument)doc.Clone();
                }
            }
            finally 
            {
                xmlReader.Close(); 
                // Whether or not parsing was successful, unblock the serializer thread. 

                // If serializer had to wait for the inline doc, it's available now. 
                // If there was an error, null will be returned for DocumentForSerialization.
                if (_waitForInlineDoc != null)
                    _waitForInlineDoc.Set();
            } 

            // warn the user if the default xmlns wasn't set explicitly (bug 1006946) 
            if (TraceData.IsEnabled) 
            {
                XmlNode root = doc.DocumentElement; 
                if (root != null && root.NamespaceURI == xmlReader.LookupNamespace(String.Empty))
                {
                    TraceData.Trace(TraceEventType.Error, TraceData.XmlNamespaceNotSet);
                } 
            }
 
            if (ex == null) 
            {
                // Load succeeded.  Create the node collection.  (This calls 
                // OnQueryFinished to reset the Document and Data properties).
                BuildNodeCollection(doc);
            }
            else 
            {
                if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ProviderQuery)) 
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.QueryFinished( 
                                            TraceData.Identify(this),
                                            Dispatcher.CheckAccess() ? "synchronous" : "asynchronous",
                                            TraceData.Identify(null),
                                            TraceData.IdentifyException(ex))); 
                }
 
                // Load failed.  Report the error, and reset 
                // Data and Document properties to null.
                OnQueryFinished(null, ex, CompletedCallback, null); 
            }
        }

        // this method can run on a worker thread! 
        private void CreateDocFromExternalSourceAsynch(object arg)
        { 
            WebRequest request = (WebRequest) arg; 
            CreateDocFromExternalSource(request);
        } 

        // this method can run on a worker thread!
        private void CreateDocFromExternalSource(WebRequest request)
        { 
            bool isExtendedTraceEnabled = TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.XmlProvider);
 
            XmlDocument doc = new XmlDocument(); 
            Exception ex = null;
            // request the content from the URI 
            try
            {
                if (isExtendedTraceEnabled)
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.XmlLoadSource( 
                                            TraceData.Identify(this), 
                                            Dispatcher.CheckAccess() ? "synchronous" : "asynchronous",
                                            TraceData.Identify(request.RequestUri.ToString()))); 
                }

                WebResponse response = WpfWebRequestHelper.GetResponse(request);
                if (response == null) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.GetResponseFailed)); 
                } 

                // Get Stream and content type from WebResponse. 
                Stream stream = response.GetResponseStream();

                if (isExtendedTraceEnabled)
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.XmlLoadDoc( 
                                            TraceData.Identify(this))); 
                }
 
                // load the XML from the stream
                doc.Load(stream);
                stream.Close();
            } 
            catch (Exception e)
            { 
                if (CriticalExceptions.IsCriticalException(e)) 
                {
                    throw; 
                }
                ex = e;
                if (TraceData.IsEnabled)
                { 
                    TraceData.Trace(TraceEventType.Error, TraceData.XmlDPAsyncDocError, Source, ex);
                } 
            } 
            //FXCop Fix: CatchNonClsCompliantExceptionsInGeneralHandlers
            catch 
            {
                throw;
            }
 
            if (ex != null)
            { 
                if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ProviderQuery)) 
                {
                    TraceData.Trace(TraceEventType.Warning, 
                                        TraceData.QueryFinished(
                                            TraceData.Identify(this),
                                            Dispatcher.CheckAccess() ? "synchronous" : "asynchronous",
                                            TraceData.Identify(null), 
                                            TraceData.IdentifyException(ex)));
                } 
 
                // we're done if we got an error up to this point
                // both .Data and .Document properties will be reset to null 
                OnQueryFinished(null, ex, CompletedCallback, null);
                return;  // have an error, no processing of DOM
            }
 
            BuildNodeCollection(doc);
            // above method also calls OnQueryFinished to push new property values 
        } 

 
        // this method can run on a worker thread!
        private void BuildNodeCollectionAsynch(object arg)
        {
            XmlDocument doc = (XmlDocument) arg; 
            BuildNodeCollection(doc);
        } 
 

        // this method can run on a worker thread! 
        private void BuildNodeCollection(XmlDocument doc)
        {
            XmlDataCollection collection = null;
            if (doc != null) 
            {
                if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.XmlBuildCollection)) 
                { 
                    TraceData.Trace(TraceEventType.Warning,
                                        TraceData.XmlBuildCollection( 
                                            TraceData.Identify(this)));
                }

                XmlNodeList nodes = GetResultNodeList(doc); 

                //we always create a new DataCollection 
                collection = new XmlDataCollection(this); 

                if (nodes != null) 
                {
                    collection.SynchronizeCollection(nodes);
                }
            } 

            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ProviderQuery)) 
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.QueryFinished( 
                                        TraceData.Identify(this),
                                        Dispatcher.CheckAccess() ? "synchronous" : "asynchronous",
                                        TraceData.Identify(collection),
                                        TraceData.IdentifyException(null))); 
            }
 
            OnQueryFinished(collection, null, CompletedCallback, doc); 

        } 

        // this callback will execute on the UI thread;
        // OnQueryFinished marshals back to UI thread if necessary
        private object OnCompletedCallback(object arg) 
        {
            if (TraceData.IsExtendedTraceEnabled(this, TraceDataLevel.ProviderQuery)) 
            { 
                TraceData.Trace(TraceEventType.Warning,
                                    TraceData.QueryResult( 
                                        TraceData.Identify(this),
                                        TraceData.Identify(Data)));
            }
 
            ChangeDocument((XmlDocument) arg);
            return null; 
        } 

        // change Document property, and update event listeners accordingly 
        private void ChangeDocument(XmlDocument doc)
        {
            if (_document != doc)
            { 
                if (_document != null)
                    UnHook(); 
 
                _document = doc;
 
                if (_document != null)
                    Hook();

                OnPropertyChanged(new PropertyChangedEventArgs("Document")); 
            }
        } 
 
        #endregion Preparing DOM
 

        // Point of no return: do not ever try to use the inline XML again.
        private void DiscardInline()
        { 
            _tryInlineDoc = false;
            _savedDocument = null; 
            if (_waitForInlineDoc != null) 
                _waitForInlineDoc.Set();
        } 

        private void Hook()
        {
            if (!_isListening) 
            {
                _document.NodeInserted += NodeChangeHandler; 
                _document.NodeRemoved += NodeChangeHandler; 
                _document.NodeChanged += NodeChangeHandler;
                _isListening = true; 
            }
        }

        private void UnHook() 
        {
            if (_isListening) 
            { 
                _document.NodeInserted -= NodeChangeHandler;
                _document.NodeRemoved -= NodeChangeHandler; 
                _document.NodeChanged -= NodeChangeHandler;
                _isListening = false;
            }
        } 

        private void OnNodeChanged(object sender, XmlNodeChangedEventArgs e) 
        { 
            if (XmlDataCollection == null)
                return; 

            UnHook();

            XmlNodeList nodes = GetResultNodeList((XmlDocument) sender); 

            // Compare the entire new list with the old, 
            // and make all the necessary insert/remove changes. 
            XmlDataCollection.SynchronizeCollection(nodes);
 
            Hook();
        }

        private XmlNodeList GetResultNodeList(XmlDocument doc) 
        {
            Debug.Assert(doc != null); 
 
            XmlNodeList nodes = null;
            if (doc.DocumentElement != null) 
            {
                // if no XPath is specified, use the root node by default
                string xpath = (string.IsNullOrEmpty(XPath)) ? "/" : XPath;
 
                try
                { 
                    if (XmlNamespaceManager != null) 
                    {
                        nodes = doc.SelectNodes(xpath, XmlNamespaceManager); 
                    }
                    else
                    {
                        nodes = doc.SelectNodes(xpath); 
                    }
                } 
                catch (XPathException xe) 
                {
                    if (TraceData.IsEnabled) 
                        TraceData.Trace(TraceEventType.Error, TraceData.XmlDPSelectNodesFailed, xpath, xe);
                }
            }
 
            return nodes;
        } 
 

        //----------------------------------------------------- 
        //
        //  Private Properties
        //
        //----------------------------------------------------- 

        private XmlDataCollection  XmlDataCollection 
        { 
            get { return (XmlDataCollection) this.Data; }
        } 

        private DispatcherOperationCallback CompletedCallback
        {
            get 
            {
                if (_onCompletedCallback == null) 
                    _onCompletedCallback = new DispatcherOperationCallback(OnCompletedCallback); 
                return _onCompletedCallback;
            } 
        }

        private XmlNodeChangedEventHandler NodeChangeHandler
        { 
            get
            { 
                if (_nodeChangedHandler == null) 
                    _nodeChangedHandler = new XmlNodeChangedEventHandler(OnNodeChanged);
                return _nodeChangedHandler; 
            }
        }

        //----------------------------------------------------- 
        //
        //  Private Fields 
        // 
        //------------------------------------------------------
 
        private XmlDocument         _document;  // the active XML DOM document
        private XmlDocument         _domSetDocument;  // a DOM set by user
        private XmlDocument         _savedDocument; // stored copy of Inline Xml for rollback
        private ManualResetEvent    _waitForInlineDoc; // serializer waits on this for inline doc 
        private XmlNamespaceManager _nsMgr;
        private Uri     _source; 
        private Uri     _baseUri; 
        private string  _xPath = string.Empty;
        private bool    _tryInlineDoc = true; 
        private bool    _isListening = false;
        private XmlIslandSerializer _xmlSerializer;
        bool            _isAsynchronous = true;
        bool            _inEndInit; 
        private DispatcherOperationCallback _onCompletedCallback;
        private XmlNodeChangedEventHandler _nodeChangedHandler; 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK