WPF assembly: XmlnsDefinition - identify types for XAML usage

by 20. June 2010 09:42

If a picture says a thousand words then the following should save me some typing as to the value of XmlnsDefinition (reference line 5 below) - it provides an easy to remember Url mapping to your namespaces. 

My PrototypeApp (born from the Prism DirectoryLookupModularity sample) has an Prototype.Interface project where much of the application specific code resides.   Within the AssemblyInfo.cs file (under the Properties folder) I was able to map all of the applicable namespaces to a single, easy to remember, url.

Excerpt from AssemblyInfo.cs follows: 

[assemblyAssemblyVersion("1.0.0.0")]
[assemblyAssemblyFileVersion("1.0.0.0")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp,
                            "PrototypeApp.Interface.Constants")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp
                           "PrototypeApp.Interface.ViewModels")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp,
                            "PrototypeApp.Interface.Controls")]
[assemblyXmlnsDefinition(http://www.Global-Webnet.com/PrototypeApp
                           "PrototypeApp.Interface.Converters")]

Demo source code follows: DirectoryLookupModularity.zip (5.82 mb)

Creating Desktop Skins in WPF for PRISM Desktop

by 13. August 2009 10:14

Based on Creating a Skinned User Interface in WPF (excellent blog on the topic!), adapted for PRISM and dependency injection.

Creating SKINS in WPF Desktop for PRISM is relatively easy.   The first thing we want to do is create our styles.  Note in my WPF Project (Demo.WPF second arrow) that I use an Assets folder - this is to be consistent with the .NET RIA Services auto generated styles (top arrow). 

My Styles.xaml file will contain styles common to all skins - in this case I have a StylesDefault (Blue) and StylesGreen (Green).

With the Styles (skins) out of the way we can start wiring up PRISM.   We do this by Loading both of the Stylesxxxxx.xaml files and registering them in our Container - the type will be ResourceDictionary with the names set to "Blue" and Default".  The code for the Windows.cs (Shell) follows:

   22 /// <summary>
   23 /// Interaction logic for Window1.xaml
   24 /// </summary>
   25 public partial class Window1 : Window
   26 {
   27     /// <summary>
   28     /// Load resources delegate
   29     /// </summary>
   30     public delegate void LoadResourcesDelegate();
   31 
   32     [Dependency]
   33     public IUnityContainer Container { get; set; }
   34 
   35     [Dependency]
   36     public ILoggerFacade Logger { get; set; }
   37 
   38     public Window1()
   39     {
   40         InitializeComponent();
   41 
   42         this.Loaded += new RoutedEventHandler(Window1_Loaded);
   43     }
   44 
   45     void Window1_Loaded(object sender, RoutedEventArgs e)
   46     {
   47         // Load asynchronously
   48         Dispatcher.BeginInvoke(new LoadResourcesDelegate(LoadResources));
   49     }
   50 
   51     private void LoadResources()
   52     {
   53         // Load secondary styles when the XAML Build Action
   54         // is set to "Content"
   55         Container.RegisterInstance<ResourceDictionary>("Blue",
   56             (ResourceDictionary)Application.LoadComponent(
   57             new Uri("Assets/StylesGreen.xaml", UriKind.Relative)));
   58 
   59         // Load default styles (so we can restore).  The XAML
   60         // Build Action is "Page" - required because the App.XAML
   61         // shows this as the MergeDictionary
   62         Container.RegisterInstance<ResourceDictionary>("Default", 
   63             (ResourceDictionary) Application.LoadComponent(
   64             new Uri("Assets/StylesDefault.xaml", UriKind.Relative)));
   65     }
   66 }

Note how we are loading the skins on their own thread (line 48).  We don't have an immediate need for the skins since our App.xaml code is loading the StylesDefault.xaml resources for it's own use (line 8 below); we don't have to affect performance by loading skins on the UI thread.

    1 <Application x:Class="Demo.WPF.App"
    2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    4 
    5     <Application.Resources>
    6         <ResourceDictionary>
    7             <ResourceDictionary.MergedDictionaries>
    8                 <ResourceDictionary Source="Assets/StylesDefault.xaml"/>
    9             </ResourceDictionary.MergedDictionaries>
   10         </ResourceDictionary>
   11     </Application.Resources>
   12 
   13 </Application>

At this point we have successfully loaded our skins into our Unity Container and are ready to wire-up a view to utilize them.

We'll now go to our Modules folder and select the ModuleClient.WPF (WPF for Desktop) and wire-up our MenuRegion's view (MainMenu) to process the available skins.  Note below we create a context menu with two menu options "Blue" (default) and "Green".

Our code behind will handle the ContextMenu_Click by using the EventAggregator to raise a MenuItem click event (ClickEventArgs handles MenuItem, Button and CheckBox clicks).   We're done on the UI side - now we'll turn our attention to the Presenter which will handle the click event.

The PrismContrib.xxxx assemblies abstract much of the framework from us (KISS).   Within these libraries resides the PresenterBase<T> which wires everything up on lines 27-32.   Once wired-up we have virtual methods that we can override to simplify our lives, e.g., below we override the OnButtonClickEventHandler to handle our MenuItem click.

The magic happens on lines 45 and 50 as applicable.  They utilize a Extensions class which extends the IUnityContainer interface.  Note how we can use the same code (line 29 below) for both Silverlight and WPF Desktop by using the "using" statements on lines 5 and 7 (below).

Line 26 will resolve our ResourceDictionary by the name effectively giving us a reference to the applicable skin dictionary.

On line 29 we get a reference to the current resource and clear it on line 33.   All that remains is to add our updated MergedDictionary and walla!  We have successfully applied a new skin.

    1 using System.Windows;
    2 using Microsoft.Practices.Unity;
    3 
    4 #if SILVERLIGHT
    5 using wpfCollection = System.Windows.PresentationFrameworkCollection<System.Windows.ResourceDictionary>;
    6 #else
    7 using wpfCollection = System.Collections.ObjectModel.Collection<System.Windows.ResourceDictionary>;
    8 #endif
    9 
   10 
   11 using System.Collections.ObjectModel;namespace Infrastructure.Resource
   12 {
   13     /// <summary>
   14     /// Resource Utility
   15     /// </summary>
   16     public static class ResourceUtil
   17     {
   18         /// <summary>
   19         /// Sets the skin.
   20         /// </summary>
   21         /// <param name="rd">The rd.</param>
   22         /// <param name="skinName">Name of the skin.</param>
   23         public static void SetSkin(this IUnityContainer container, string skinName)
   24         {
   25 #if !WinForm
   26             ResourceDictionary skin =
   27                 container.Resolve<ResourceDictionary>(skinName);
   28 
   29             wpfCollection mergedDicts =
   30                 Application.Current.Resources.MergedDictionaries;
   31 
   32             if (mergedDicts.Count > 0)
   33                 mergedDicts.Clear();
   34 
   35             // Apply the selected skin so that all elements in the
   36             // application will honor the new look and feel.
   37             mergedDicts.Add(skin);
   38 #endif
   39 
   40         }
   41     }
   42 }

Right clicking on the Menu bar (top sky-blue region) reveals our context menu. 

Tags: , ,

WPF

How to use .NET RIA Services in PRISM

by 27. July 2009 21:20

For Webcast overview of process CLICK HEREImportant note: the Presenter being shown on the screen during the Webcast is actually being utilized by the Silverlight, RIA, WPF and Winforms applications (they all utilize the PRISM framework using the Model-View-Presenter and Model-View-ViewModel patterns - see architectural note at end of blog). 

Tim Heuer's presentation on RIA services for Silverlight 3
http://silverlight.net/learn/learnvideo.aspx?video=245417

Tim Heuer does an excellent presentation of RIA services on the above link.   The problem for PRISM developers is that the RIA data access layer resides in the presentation layer’s bootstrap application RIABusApp (ref image below).   Since our RIABusApp will reference our module(s) this poses a problem because now our modules cannot reference our RIA data layer (which resides in RIABusApp) because of a circular reference.   The key to making real RIA work with PRISM is to be able to have the modules reference the bootstrap application RIABusApp.

Fortunately Silverlight allows us to load assemblies dynamically.  With a few lines of code we can load the module and call its initialize mapping without ever having made a reference to the Module.  This is practical with PRISM because most of the business logic will reside in a module minimizing the requirement for any references in RIABusApp.

Code follows:

using System;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Composite.Modularity;
using Microsoft.Practices.Unity;
using PrismContrib.Base;
using PrismContrib.Events;
using PrismContrib.Interfaces;

namespace RIABusApp
{
    public partial class App : Application
    {
        private IBootstrapperProcess bootstrapperProcess = null;

        [Dependency]
        public IUnityContainer Container { get; set; }
        private IUnityContainer container; 

        public App()
        {
            this.Startup += this.Application_Startup;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        void Application_Startup(object sender, StartupEventArgs e)
        {
            this.Resources.Add("RiaContext", RiaContext.Current);
            Bootstrapper<MainPage> bootstrap = new Bootstrapper<MainPage>();
            bootstrap.OnConfigureContainer += OnConfigureContainer;
            bootstrap.OnInitializeModules += OnInitializeModules;
            bootstrap.InitParams = e.InitParams;
            bootstrap.Run();
        }
        /// <summary>
        /// Dynamically load the Mapping Module because it will have
        /// a reference set to this assembly to gain access to the
        /// Services\DataLayerDefault class
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="PrismContrib.Events.BootStrapperEventArgs"/>
        /// instance containing the event data.</param>
        void OnInitializeModules(object sender, BootStrapperEventArgs e)
        {
            container = e.Container;
            WebClient client = new WebClient();

            client.OpenReadCompleted +=
                new OpenReadCompletedEventHandler(OnAssemblyOpened);

            // Requires assembly to be in the RIABusApp.Web ClientBin folder
            client.OpenReadAsync(
                new Uri("ISO15926.Module.Mapping.Silverlight.dll", UriKind.Relative));
        }
        void OnAssemblyOpened(object sender, OpenReadCompletedEventArgs e)
        {
            AssemblyPart assemblyPart = new AssemblyPart();
            Assembly assembly = assemblyPart.Load(e.Result);

            // Find our mapping module in the list returned by GetTypes
            Type mappingType = assembly.GetTypes()
                .First(m => m.FullName.Contains("MappingModule"));

            // Dynamically instantiate our module
            IModule module = (IModule) Activator.CreateInstance(mappingType);

            if (module != null)
            {
                // Buildup doesn't seem to be working on dynamically
                // created class...  Will set container manually
                // => container.BuildUp(module);
                ((IContainer)module).Container = container;
                module.Initialize();
            }
        }

        void OnConfigureContainer(object sender, PrismContrib.Events.BootStrapperEventArgs e)
        {
            e.Container.RegisterType<IControlProcessor, ControlProcessorWPF>();
        }

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // a ChildWindow control.
            if (!System.Diagnostics.Debugger.IsAttached)
            {
                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled.
                // For production applications this error handling should be replaced with something that will
                // report the error to the website and stop the application.
                e.Handled = true;
                ChildWindow errorWin = new ErrorWindow(e.ExceptionObject);
                errorWin.Show();
            }
        }
    }
}

The application that we're using for this blog is a multi-targeting application; this means that we can have multiple platforms using the same code (as shown in the projects underlined above).  In this case RIA Services will be utilizing the Silverlight module.  Below you'll see all of the client side code that is required to return a class list, as Tim noted in his presentation all of the projection is handled for us.

The code on server side is no more complicated as shown below.

In PRISM, because of dependency injection, all we have to do to consume our service is request a reference to IDataService (constructor injection), request the classes and assign the results to the model.Classes property.

Note: The SemWeb infrastructure (which utilizes my own PRISMContrib project) handles the event notification for us.   SemWeb is scheduled to be released late August at http://www.CodePlex.com/SemWeb.

The source code for the MappingPresenter follows: 

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using ISO15926.Library;
using ISO15926.Module.Mapping.Services;
using Microsoft.Practices.Unity;
using Microsoft.Windows.Controls;
using PrismContrib.Base;
using PrismContrib.Events;

namespace ISO15926.Module.Mapping.Views.InformationModel
{
    /// <summary>
    /// Information Model presenter
    /// </summary>
    public class InformationModelPresenter : PresenterBase<IInformationModelView>
    {
        private ISemWebPresentationModel model;

        private DataGrid grdClasses {
            get { return GetControl<DataGrid>("dgClasses"); }
        }

        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="InformationModelPresenter"/> class.
        /// </summary>
        /// <param name="view">The view.</param>
        /// <param name="model">The model.</param>
        /// <param name="container">The container.</param>
        /// <param name="riaDAL">The ria DAL.</param>
        public InformationModelPresenter(
            IInformationModelView view,
            ISemWebPresentationModel model,
            IUnityContainer container,
            IDataService riaDAL) : base(view, model, container)
        {
            this.model = model;

            // Populate model with ISO15926 Class
            model.Classes = riaDAL.GetClassList();
        }

        private void OnDataLoaded()
        {
            grdClasses.ItemsSource = model.Classes;
        }

        #region OVERRIDES of baseclass methods  

        #region METHOD: OnViewSizeSet
        /// <summary>
        /// Called when [view size set].  Sets the data grid dimensions
        /// to the current view
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.SizeChangedEventArgs"/> instance containing the event data.</param>
        protected override void OnViewSizeSet(object sender, SizeChangedEventArgs e)
        {
            // Filter for this view
            IInformationModelView view = sender as IInformationModelView;
            if (view == null)
                return;

            // Set grid height and width to view dimensions so that
            // we'll have scrollbars
            grdClasses.Height = e.NewSize.Height;
            grdClasses.Width = e.NewSize.Width;

            base.OnViewSizeSet(sender, e);
        }
       
        #endregion
        #region METHOD: OnButtonClickEventHandler
        /// <summary>
        /// Handles all Button/CheckBox Click events
        /// <see cref="E:ClickEventHandler"/>
        /// </summary>
        /// <param name="e">The <see cref="ClickEventArgs"/>
        /// instance containing the event data.</param>
        public override void OnButtonClickEventHandler(ClickEventArgs e)
        {
            e.IsHandled = e.Name.Contains("DetailsView_ClickMe");

            if (e.IsHandled)
                MessageBox.Show(string.Format("ISO159296 Classes record count = {0}",
                        model.Classes.Count));

            base.OnButtonClickEventHandler(e);

        }
       
        #endregion
        #region METHOD: OnDALEventHandler
        /// <summary>
        /// Raises the <see cref="E:DALEventHandler"/> event.
        /// </summary>
        /// <param name="e">The <see cref="PrismContrib.Events.DALEventArgs"/>
        /// instance containing the event data.</param>
        public override void OnDALEventHandler(DALEventArgs e)
        {
            // We're only interested in IsLoading context property changes
            if (e.IsPropertyChange && e.PropertyName.Contains("IsLoading"))
            {
                if (!e.IsLoading)
                {
                    e.IsHandled = true;  // notify logging we handled it
                    base.OnDALEventHandler(e);
                    OnDataLoaded();
                }
            }
            else  // For logging purposes
                base.OnDALEventHandler(e);

        }
       
        #endregion       
        #region METHOD: OnModelPropertyChanged 

        /// <summary>
        /// Called when [model property changed].  Intended to be overridden
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/>
        /// instance containing the event data.</param>
        public override void OnModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
#if !SILVERLIGHT
            // WPF/WinForms are using stub data so there is no callback method
            // to trigger OnDataLoaded() - we'll fire it manually on
            // ModelPropertyChanged
            if (e.PropertyName.Contains("Classes"))
                OnDataLoaded();
#endif
        }
       
        #endregion        

        #endregion
    }
}
 

Architectural note:  This application uses a combination of the Model-View-Presenter (MVP) pattern and the Model-View-ViewModel (MVVM) pattern, aka Presentation Model and Application Model.    By having multiple views share the same model (see Martin Fowlers Presentation Model) you can effectively share the same data without having to have a lot of complex logic to maintain state.   Each view can update the model and the other views will be notified via the observer pattern (INotifyPropertyChanged).

Trying to use MVVM alone has introduced the limitations that Martin Fowler discussed in THIS ARTICLE (paragraph above Figure 11).   As he suggest, it was the limitations that introduced the need for MVP.   Combining them gives us the best of both worlds.  

 

Where is Microsoft.Expression.Interactions?

by 21. July 2009 10:09

That's the question I was asking after installing Microsoft Expression Blend 3.   It appears that two DLL references are missing - or at least misplaced.

They are located at C:\Program Files\Microsoft SDKs\Expression\Blend 3\Interactivity\Libraries. 

In my case (64bit) it was C:\Program Files(x86)\... as shown in the image that follows.

Add the references and all will be happy. 

Below you can see that after adding references our view will display.   Note Expression Blend 3 offers 140 controls! 

WPF - setting background color of control programmatically

by 26. September 2008 01:48

Searching for a way to set the background color of a WPF control programmatically seemed like more of an adventure then it should have been; there are sure a lot of complicated ways to set a background color.   Reluctant to believe that it was this complicated I kept searching until I found it.

txtStatus.Foreground = new SolidColorBrush(Colors.White);
txtStatus.Background = new SolidColorBrush(Colors.Red);

Tags: ,

WPF

CompositeWPF - Getting your view to stretch vertically as well as horizontally

by 9. August 2008 00:25

My primary view (loaded in the Shell's MainRegion) looked as follows; I want my menu bar at the top, a status bar at the bottom and the ProcessSolutionRegion contents to fill in the middle:

The result follows - not exactly what I was expection or needing...  I need my status bar to be at the bottom.

If I were to wrap my Grid with a DockPanel and specify a height I get what I'm looking for - at least until I resize my Window....

FYI, wrapping the ItemsControl in the Shell doesn't work:

<DockPanel Height="265">
<ItemsControl Name="MainRegion"
            cal:RegionManager.RegionName="{x:Static local:RegionNames.MainRegion}"/>
</DockPanel>

I have to add a Template to my ItemsControl element to get my desired results:

<Window x:Class="ShellApp.Shell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="http://www.codeplex.com/CompositeWPF"
    xmlns:local="clr-namespace:ShellApp"
    Name="myShell" Title="GWN App" Height="300" Width="300">
   
    <ItemsControl Name="MainRegion"
            cal:RegionManager.RegionName="{x:Static local:RegionNames.MainRegion}">
       
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <DockPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
       
    </ItemsControl>
</Window>

 

CompositeWPF - Using a single interface for multiple services

by 30. July 2008 13:05

In the following message Multiple views of the same data CodeHulk clarifies some requirements that will allow us to exercise the power of Unity to decouple services.

The XAML code for the HelloWorldView.xaml file:

<UserControl x:Class="HelloWorld.Views.HelloWorldView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:HelloWorld"
    xmlns:cal="http://www.codeplex.com/CompositeWPF">
   
    <StackPanel>
        <TextBlock x:Name="lblResults" HorizontalAlignment="Center">HelloWorld</TextBlock>
        <Button Click="btnClick" x:Name="btnOne">Load HelloWorld1</Button>
        <Button Click="btnClick" x:Name="btnTwo">Load HelloWorld2</Button>
        <ContentControl
                     cal:RegionManager.RegionName="{x:Static local:RegionNames.HelloWorld}"/>
    </StackPanel>
</UserControl>

It produces the following output:

Both buttons subscribe to the same btnClick() method in the above XAML - this is where all the magic happens.

    public partial class HelloWorldView : UserControl
    {
        private IUnityContainer _container;
        public HelloWorldView(IUnityContainer container)
        {
            InitializeComponent();
            _container = container;
        }

        private void btnClick(object sender, System.Windows.RoutedEventArgs e)
        {
            Button button = sender as Button;
            IHelloWorldService service = _container.Resolve<IHelloWorldService>(button.Name);
            lblResults.Text = service.GetMessage();
        }
    }

The button.Name will contain the string "btnOne" or "btnTwo", depending on the button that was clicked.  Since a name is provided the container will search the registered IHelloWorldService services and resolve to the applicable class.   The classes are defined in the modules RegisterViewsAndServices() method below:

    public class HelloWorldModule : IModule
    {
        private readonly IRegionManager regionManager;
        private readonly IUnityContainer container;

        public HelloWorldModule(IRegionManager regionManager, IUnityContainer container)
        {
            this.regionManager = regionManager;
            this.container = container;
        }

        public void Initialize()
        {
            IRegion mainRegion = this.regionManager.Regions[RegionNames.MainRegion];

            RegisterViewsAndServices();
           
            mainRegion.Add( container.Resolve<HelloWorldView>());
        }
        protected void RegisterViewsAndServices()
        {
            container
                .RegisterType<IHelloWorldService, HelloWorldService1>("btnOne")
                .RegisterType<IHelloWorldService, HelloWorldService2>("btnTwo");
           
        }
    }

The actual interface,  services and button click results follow:

    public interface IHelloWorldService
    {
        string GetMessage();
    }

    public class HelloWorldService1 : IHelloWorldService
    {
        public string GetMessage()
        {
            return "********> Hello World #1 <********";
        }
    }

    public class HelloWorldService2 : IHelloWorldService
    {
        public string GetMessage()
        {
            return "======> Hello World #2 <======";
        }
    }

Source Code: HelloWorld.zip (546.51 kb)

XBAP - Deploying to CompositeWPF to IIS Server

by 30. July 2008 11:18

In the following CodePlex message Can I develop XBAP application with this framework?   sjappie alerts me to the fact that the CompositeWPF XBAP application will not deploy and run in IIS - so far I've only used it in Visual Studio 2008 Debug mode; I confirmed that what he was saying was true.

I found this blog How to run WPF - XBAP as Full Trust Application to be very thorough on explaining how to configure an XBAP application so that it can run in a full-trust environment.  After complying with the steps the CompositeWPF Command demo will now run in IIS.


Click Image to view Flash Demo

Related post by the same author:
How to run WPF-XBAP Application in Full-Trust Mode (Post #2: certificate extraction)

WPF - the next big adventure...

by 20. July 2008 06:45

In Adam Nathan's "Windows Presentation Foundation Unleashed" introduction, Adam shares with us that the learning curve for WPF is "very steep"; an excerpt follows:

Even viewing the source code for WPF (by cracking open its components with a tool like .NET Reflector) is a confusing experience because the code you’re looking for often doesn’t reside where you’d expect. When you combine all of this with the fact that there are often several ways to accomplish any task,you arrive at a conclusion shared by many: WPF has a very steep learning curve.

FORTUNATELY, Microsoft is helping us with free webcast to understand WPF and minimize this learning curve.  Important link follows:

http://msdnevents.com/live-webcasts.aspx - click on the WebCast link and type in WPF; you won't find all 18 webcast but they are there (they aren't caught in the filtered search).   I am on lesson 12 of 18 (each lesson is approximately an hour), which lead me to the above referenced book.  I plan to complete the webcast series and the book before attempting to dissect and understand the ComposteWPF.  Note: I created an Access database to index the content and it's location within each webcast, e.g., to locate Expression Blend tutorials such as an early one where Bill Steele rotates his plane (current index here: Index.mdb (588.00 kb) - it may only have meaning to me however I'll make it available as it is updated - just in case...)

The CompositeWPF (aka Prism) is where my introduction to WPF emerged - I downloaded one of the early Prism drops and was totally lost!  Even with my knowledge of MVP and the Object Builder I knew nothing of Dependency Injection.  After hours of research I started to grasp glimmers of understanding for the voodoo I was observing- which Glenn Block offered assistence with HERE.   Today, with much patience from folks like Chris Tavares (patience with my ignorant questions and statements) I see the light.  Unity rocks and I plan to write numerous blogs that will help others who have no experience with Dependency Injection, and worse yet - no knowledge of MVP understand its power.

 

Notice

Blog videos and references to CodePlex projects are no longer valid