Click here to Skip to main content
13,732,747 members
Click here to Skip to main content

Stats

57K views
4.6K downloads
55 bookmarked
Posted 7 Dec 2011
Licenced CPOL

Building WPF Applications with Self-Tracking Entity Generator - Project Setup

, 20 Feb 2012
This article describes the project setup of building a WPF sample application with Self-Tracking Entity Generator for WPF/Silverlight.
SchoolSample
Local.testsettings
SchoolSample.vsmdi
TraceAndTestImpact.testsettings
Assemblies
GalaSoft.MvvmLight.Extras.WPF4.dll
GalaSoft.MvvmLight.WPF4.dll
Moq.dll
System.Windows.Interactivity.dll
WPFToolkit.Extended.dll
ComponentModel.Composition.Initialization.Desktop
Microsoft
ComponentModel
Composition
Hosting
Internal
Properties
System
ComponentModel
Composition
Hosting
System.Windows.Controls.Data.Input
Common
Properties
themes
Validation
Database
SchoolSample
SchoolSample.csproj.user
Asset
Control
Properties
View
SchoolSample.Common
Model
Properties
Resource
SchoolSample.Data
EntityModel
Properties
Validation
SchoolSample.Data.Wcf
App.Config
EntityModel
SchoolModel.edmx
Properties
Validation
SchoolSample.Model
Properties
SchoolSample.ViewModel
Properties
SchoolSample.Wcf
SchoolSample.Wcf.csproj.user
Properties
Service
SchoolService.svc
SchoolSample.WCFService
SchoolSample.WCFService.csproj.user
Properties
Service References
SchoolService
configuration.svcinfo
configuration91.svcinfo
Reference.svcmap
SchoolService.disco
Test.SchoolSample.Model
Properties
Test References
SchoolSample.Model.accessor
Test.SchoolSample.ViewModel
Properties
Test References
SchoolSample.ViewModel.accessor
Local.testsettings
SchoolSample.vsmdi
TraceAndTestImpact.testsettings
GalaSoft.MvvmLight.Extras.WPF4.dll
GalaSoft.MvvmLight.WPF4.dll
Moq.dll
System.Windows.Interactivity.dll
WPFToolkit.Extended.dll
SchoolSample.csproj.user
App.Config
SchoolModel.edmx
SchoolSample.Wcf.csproj.user
SchoolService.svc
SchoolSample.WCFService.csproj.user
configuration.svcinfo
configuration91.svcinfo
Reference.svcmap
SchoolService.disco
SchoolSample.Model.accessor
SchoolSample.ViewModel.accessor
Local.testsettings
SchoolSample.vsmdi
TraceAndTestImpact.testsettings
GalaSoft.MvvmLight.Extras.WPF4.dll
GalaSoft.MvvmLight.WPF4.dll
Moq.dll
System.Windows.Interactivity.dll
WPFToolkit.Extended.dll
SchoolSample.csproj.user
App.Config
SchoolModel.edmx
SchoolSample.Wcf.csproj.user
SchoolService.svc
SchoolSample.WCFService.csproj.user
configuration.svcinfo
configuration91.svcinfo
Reference.svcmap
SchoolService.disco
SchoolSample.Model.accessor
SchoolSample.ViewModel.accessor
// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading;
using Microsoft.Internal;

#if (SILVERLIGHT)
namespace System.ComponentModel.Composition.Hosting
{
    /// <summary>
    /// Implements a MEF catalog that supports Asynchronous download of Silverlast Xap files.
    /// </summary>
    public class DeploymentCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
    {
        static class State
        {
            public const int Created = 0;
            public const int Initialized = 1000;
            public const int DownloadStarted = 2000;
            public const int DownloadCompleted = 3000;
            public const int DownloadCancelled = 4000;
        }

        private Lock _lock = new Lock();
        private volatile bool _isDisposed = false;
        private Uri _uri = null;
        private int _state = State.Created;
        private AggregateCatalog _catalogCollection = new AggregateCatalog();
        private WebClient _webClient = null;

        /// <summary>
        /// Construct a Deployment catalog with the parts from the main Xap.
        /// </summary>
        public DeploymentCatalog()
        {
            this.DiscoverParts(Package.CurrentAssemblies);
            this._state = State.Initialized;
        }

        /// <summary>
        /// Construct a Deployment catalog with a string form relative uri.
        /// </summary>
        /// <value>
        ///     A relative Uri to the Download Xap file
        ///     <see cref="DeploymentCatalog"/>.
        /// </value>
        /// <exception cref="ArgumentException">
        ///     The argument is null or an empty string.
        /// </exception>
        public DeploymentCatalog(string uriRelative)
        {
            Requires.NotNullOrEmpty(uriRelative, "uriRelative");
            this._uri = new Uri(uriRelative, UriKind.Relative);
        }

        /// <summary>
        /// Construct a Deployment catalog with the parts from uri.
        /// </summary>
        /// <value>
        ///     A Uri to the Download Xap file
        ///     <see cref="System.Uri"/>.
        /// </value>
        /// <exception cref="ArgumentException">
        ///     The argument is null.
        /// </exception>
        public DeploymentCatalog(Uri uri)
        {
            Requires.NotNull<Uri>(uri, "uri");
            this._uri = uri;
        }

        /// <summary>
        /// Notify when the contents of the Catalog has changed.
        /// </summary>
        public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed;

        /// <summary>
        /// Notify when the contents of the Catalog is changing.
        /// </summary>
        public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing;

        /// <summary>
        /// Notify when the download has been completed.
        /// </summary>
        public event EventHandler<AsyncCompletedEventArgs> DownloadCompleted;

        /// <summary>
        /// Notify when the contents of the Progress of the download has changed.
        /// </summary>
        public event EventHandler<DownloadProgressChangedEventArgs> DownloadProgressChanged;
       
        /// <summary>
        /// Retrieve or create the WebClient.
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        ///     The <see cref="DeploymentCatalog"/> has been disposed of.
        /// </exception>
        private WebClient WebClient
        {
            get
            {
                this.ThrowIfDisposed();
                if(this._webClient == null)
                {
                    Interlocked.CompareExchange<WebClient>(ref this._webClient, new WebClient(), null);
                }
                return this._webClient;
            }
        }
        
        /// <summary>
        ///     Gets the part definitions of the Deployment catalog.
        /// </summary>
        /// <value>
        ///     A <see cref="IQueryable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the 
        ///     <see cref="DeploymentCatalog"/>.
        /// </value>
        /// <exception cref="ObjectDisposedException">
        ///     The <see cref="DeploymentCatalog"/> has been disposed of.
        /// </exception>
        public override IQueryable<ComposablePartDefinition> Parts
        {
            get
            {
                this.ThrowIfDisposed();
                return this._catalogCollection.Parts;
            }
        }

        /// <summary>
        ///     Gets the Uri of this catalog
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        ///     The <see cref="DeploymentCatalog"/> has been disposed of.
        /// </exception>
        public Uri Uri
        {
            get
            {
                this.ThrowIfDisposed();
                return this._uri;
            }
        }

        /// <summary>
        /// </summary>
        /// <param name="assemblies">
        /// </param>
        /// <exception cref="ObjectDisposedException">
        ///     The <see cref="DeploymentCatalog"/> has been disposed of.
        /// </exception>
        private void DiscoverParts(IEnumerable<Assembly> assemblies)
        {
            this.ThrowIfDisposed();

            var addedDefinitions = new List<ComposablePartDefinition>();
            var addedCatalogs = new Dictionary<string, ComposablePartCatalog>();
            using(new ReadLock(this._lock))
            {
                foreach (var assembly in assemblies)
                {
                    if (addedCatalogs.ContainsKey(assembly.FullName)) 
                    {
                        // Nothing to do because the assembly has already been added.
                        continue;
                    }

                    var catalog = new AssemblyCatalog(assembly);
                    addedDefinitions.AddRange(catalog.Parts);
                    addedCatalogs.Add(assembly.FullName, catalog);
                }
            }

            // Generate notifications
            using (var atomicComposition = new AtomicComposition())
            {
                var changingArgs = new ComposablePartCatalogChangeEventArgs(addedDefinitions, Enumerable.Empty<ComposablePartDefinition>(), atomicComposition);
                this.OnChanging(changingArgs);

                using (new WriteLock(this._lock))
                {
                    foreach (var item in addedCatalogs)
                    {
                        this._catalogCollection.Catalogs.Add(item.Value);
                    }
                }
                atomicComposition.Complete();
            }

            var changedArgs = new ComposablePartCatalogChangeEventArgs(addedDefinitions, Enumerable.Empty<ComposablePartDefinition>(), null);
            this.OnChanged(changedArgs);
        }

        /// <summary>
        ///     Returns the export definitions that match the constraint defined by the specified definition.
        /// </summary>
        /// <param name="definition">
        ///     The <see cref="ImportDefinition"/> that defines the conditions of the 
        ///     <see cref="ExportDefinition"/> objects to return.
        /// </param>
        /// <returns>
        ///     An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the 
        ///     <see cref="ExportDefinition"/> objects and their associated 
        ///     <see cref="ComposablePartDefinition"/> for objects that match the constraint defined 
        ///     by <paramref name="definition"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="definition"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ObjectDisposedException">
        ///     The <see cref="DeploymentCatalog"/> has been disposed of.
        /// </exception>
        public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
        {
            this.ThrowIfDisposed();
            Requires.NotNull(definition, "definition");

            return this._catalogCollection.GetExports(definition);
        }

        /// <summary>
        /// Cancel the async operation.
        /// </summary>
        public void CancelAsync()
        {
            ThrowIfDisposed();
            MutateStateOrThrow(State.DownloadCancelled, State.DownloadStarted);
            this.WebClient.CancelAsync();
        }

        /// <summary>
        /// Begin the asynchronous download.
        /// </summary>
        public void DownloadAsync()
        {
            ThrowIfDisposed();

            if (Interlocked.CompareExchange(ref this._state, State.DownloadStarted, State.Created) == State.Created)
            {
                // Created with Downloadable content do download
                this.WebClient.OpenReadCompleted += new OpenReadCompletedEventHandler(HandleOpenReadCompleted);
                this.WebClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(HandleDownloadProgressChanged);
                this.WebClient.OpenReadAsync(Uri, this);
            }
            else
            {
                // Created with LocalAssemblies 
                MutateStateOrThrow(State.DownloadCompleted, State.Initialized);

                this.OnDownloadCompleted(new AsyncCompletedEventArgs(null, false, this));
            }
        }

        void HandleDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            EventHandler<DownloadProgressChangedEventArgs> downloadProgressChangedEvent = this.DownloadProgressChanged;
            if (downloadProgressChangedEvent != null)
            {
                downloadProgressChangedEvent(this, e);
            }
        }

        private void HandleOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            Exception error = e.Error;
            bool cancelled = e.Cancelled;

            // Possible valid current states are DownloadStarted and DownloadCancelled.
            int currentState = Interlocked.CompareExchange(ref this._state, State.DownloadCompleted, State.DownloadStarted);

            if (currentState != State.DownloadStarted)
            {
                cancelled = true;
            }

            if (error == null && !cancelled)
            {
                try
                {
                    var assemblies = Package.LoadPackagedAssemblies(e.Result);
                    this.DiscoverParts(assemblies);
                }
                catch (Exception ex)
                {
                    error = new InvalidOperationException(Strings.InvalidOperationException_ErrorReadingXap, ex);
                }
            }

            this.OnDownloadCompleted(new AsyncCompletedEventArgs(error, cancelled, this));
        }

        /// <summary>
        ///     Raises the <see cref="INotifyComposablePartCatalogChanged.Changed"/> event.
        /// </summary>
        /// <param name="e">
        ///     An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event.
        /// </param>
        protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e)
        {
            EventHandler<ComposablePartCatalogChangeEventArgs> changedEvent = this.Changed;
            if (changedEvent != null)
            {
                changedEvent(this, e);
            }
        }

        /// <summary>
        ///     Raises the <see cref="INotifyComposablePartCatalogChanged.Changing"/> event.
        /// </summary>
        /// <param name="e">
        ///     An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event.
        /// </param>
        protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e)
        {
            EventHandler<ComposablePartCatalogChangeEventArgs> changingEvent = this.Changing;
            if (changingEvent != null)
            {
                changingEvent(this, e);
            }
        }

        /// <summary>
        ///     Raises the <see cref="DownloadCompleted"/> event.
        /// </summary>
        /// <param name="e">
        ///     An <see cref="AsyncCompletedEventArgs"/> containing the data for the event.
        /// </param>
        protected virtual void OnDownloadCompleted(AsyncCompletedEventArgs e)
        {
            EventHandler<AsyncCompletedEventArgs> downloadCompletedEvent = this.DownloadCompleted;
            if (downloadCompletedEvent != null)
            {
                downloadCompletedEvent(this, e);
            }
        }

        /// <summary>
        ///     Raises the <see cref="DownloadProgressChanged"/> event.
        /// </summary>
        /// <param name="e">
        ///     An <see cref="ProgressChangedEventArgs"/> containing the data for the event.
        /// </param>
        protected virtual void OnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
        {
            EventHandler<DownloadProgressChangedEventArgs> downloadProgressChangedEvent = this.DownloadProgressChanged;
            if (downloadProgressChangedEvent != null)
            {
                downloadProgressChangedEvent(this, e);
            }
        }

        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    if (!this._isDisposed)
                    {
                        AggregateCatalog catalogs = null;
                        bool disposeLock = false;
                        try
                        {
                            using (new WriteLock(this._lock))
                            {
                                if (!this._isDisposed)
                                {
                                    disposeLock = true;
                                    catalogs = this._catalogCollection;
                                    this._catalogCollection = null;
                                    this._isDisposed = true;
                                }
                            }
                        }
                        finally
                        {
                            if (catalogs != null)
                            {
                                catalogs.Dispose();
                            }

                            if (disposeLock)
                            {
                                this._lock.Dispose();
                            }
                        }
                    }
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }

        private void ThrowIfDisposed()
        {
            if (this._isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().ToString()); 
            }
        }

        private void MutateStateOrThrow(int toState, int fromState)
        {
            int currentState = Interlocked.CompareExchange(ref this._state, toState, fromState);
            if(currentState != fromState)
            {
                throw new InvalidOperationException(Strings.InvalidOperationException_DeploymentCatalogInvalidStateChange);
            }
        }
    }
}
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Weidong Shen
Software Developer (Senior)
United States United States
Weidong has been an information system professional since 1990. He has a Master's degree in Computer Science, and is currently a MCSD .NET

You may also be interested in...

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05-2016 | 2.8.180920.1 | Last Updated 20 Feb 2012
Article Copyright 2011 by Weidong Shen
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid