SDMS - Using the Logger (TraceTool) to aid development

Our SDMS main view takes advantage of routed events - we'll subscribe all button clicks to the UserControl_Click event handler. 

<UserControl x:Class="MainView"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   x:Name="MainViewUC"

   ButtonBase.Click="UserControl_Click"> 

 

    <DockPanel>

        <Menu DockPanel.Dock="Top">

            <MenuItem Header="File"/>

            <MenuItem Header="Tools"/>

            <MenuItem Header="Help"/>

        </Menu>

Since all routed events will be processed by a single method in our presenter we can use the Factory Pattern to process them.  For extensibility purposes we won't assume that the routed event will always be a button click. 

Typically you might place a break point on line 43 to determine what properties can be used to create the factory - we'll let the Logger (TraceTool) assist us here:

In our demo we clicked the "Toolbox" vertical button.

Below we see that we can use the e.RoutedEvent property to determine which class should be resolved to handle event processing, in this case "ButtonBase.Click".   The e.OriginalSource can be used to determine what Command should be executed within the resolved class.  

Click HERE for flash demo 
http://www.codeplex.com/SDMS | Source Code Tab | Change Set: 23138

Click HERE for flash demo

 


Tags: , , ,
Categories: CompositeWPF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

CompositeWPF - Hijacking the Logger

For reasons that will become readily apparent I am replacing the default logger with TraceTool - the CompositeWPF documentation pretty much tells us to do it as follows in the bootstrapper:

        private TraceToolLogger logger = new TraceToolLogger();
        /// <summary>
        /// Override loggerFacade to use the TraceToolLogger
        /// </summary>
        protected override ILoggerFacade LoggerFacade
        {
            get
            {
                return logger;
            }
        }

This is easy!  The only problem is we have only one Log method with the ILoggerFacade and I want to take advantage of all the power the TraceTool offers while providing backwards compatibility with all existing log calls; the ILoggerFacade interface follows:

    public interface ILoggerFacade
    {
        void Log(string message, Category category, Priority priority);
    }

I'll let Polymorphism help me here - note above I am using TraceToolLogger.  The TraceToolLogger code below reveals that it implements my new ILogger interface! 

namespace CompositeWPF.Library.Core
{
    public class TraceToolLogger : ILogger
    {
        public void Log(string message, Category category, Priority priority)
        {
            string leftMsg = string.Format("{0}[{1}]", category, priority);
            switch (category)
            {
                case Category.Debug:
                    TTrace.Debug.Send(leftMsg, message);
                    break;
                case Category.Exception:
                    TTrace.Error.Send(leftMsg, message);
                    break;
                case Category.Info:
                    TTrace.Debug.Send(leftMsg, message);
                    break;
                case Category.Warn:
                    TTrace.Warning.Send(leftMsg, message);
                    break;
            }
        }

        public void Log(string leftMsg, object objToSend, TraceDisplayFlags flag)
        {
            TTrace.Debug.SendObject(leftMsg, objToSend, flag);
        }
        /// <summary>
        /// Shows object fields
        /// </summary>
        /// <param name="leftMsg"></param>
        /// <param name="objToSend"></param>
        public void Log(string leftMsg, object objToSend)
        {
            Log(leftMsg, objToSend, TraceDisplayFlags.ShowFields);
        }
    }

By implementing the ILoggerFacade interface on my ILogger interface I'll be allowed to assign the TraceToolLogger instance to the LoggerFacade; my TraceToolLogger will be backwards compatible while making ILogger available for dependency injection.

namespace CompositeWPF.Library.Interface.Interfaces
{
    public interface ILogger : ILoggerFacade
    {
        void Log(string leftMsg, object objToSend, TraceDisplayFlags flag);
        void Log(string leftMsg, object objToSend);
    }
}

Click HERE for flash demo

The above output resulted from the below code.  I am using the TraceTool SendObject() method to display the class contents - in this case of Test.   This will permit me to debug trace objects and their contents which will become invaluable when I start plugging in my SQL Server stored procedure calls - I'll be able to output my parameter object so that I can see at a glance what is being sent to the backend - AND - what is being returned.

Source code available HERE - Change Set: 22520

 


Tags: , ,
Categories: CompositeWPF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

CompositeWPF - Displaying Loading... message while form loads

Below we'll show how to display a loading message while we wait for our form to load - we'll display the form almost immediately.

The QuickStarts \ Commanding \ App.xaml.cs has the following code:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        CommandingBootstrapper bootstrapper = new CommandingBootstrapper();
        bootstrapper.Run();
    }
}

Which has the bootstrapper loading the Shell and showing it

class CommandingBootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        Shell shell = Container.Resolve<Shell>();
        shell.Show();
        return shell;
    }
    protected override IModuleEnumerator GetModuleEnumerator()
    {
        return new StaticModuleEnumerator().AddModule(typeof(OrderModule));
    }
}

Since the SDMS solution has the bootstrapper in the CompositeWPF.Library we can't use the above code so we provide the BootStrapper a delegate for the CreateShell method that it should call.   The SDMS \ App \ CommandPrototype application has the following:

public partial class App : Application
{
    public App()
    {
        BootStrapper bootStrapper = new BootStrapper(CreateShell, GetType());
        bootStrapper.Run();
    }
    protected DependencyObject CreateShell(IUnityContainer container)
    {
        // Launch our shell
        Window1 shell = container.Resolve<Window1>();
        shell.Show();
        return shell;
    }
}

With both of the above configurations note how much time transpires from the time the Bootstrapper is started (21:22:30:102) to the time the Shell normally is displayed (21:22:31:205 - the arrow). 

We won't use the above two default methods of loading and showing the form when the BootStrapper.CreateShell() method fires; we want to show a "Loading..." message.  As you can see in the screenshot below the *first* thing we do is load the form and show it - we then start loading the application.

After the Shell is loaded (21:22:32:290) the CompositeWPF then proceeds to load and initialize modules - whether using the new process or default the form is displayed while loading continues...

The following reflects what the SDMS user will see almost immediately - until the form is completely loaded.  The loading message is in a textblock which can be replaced with pictures or progressbar (being updated at strategic intervals); for now I'm going for core functionality.

What the user sees after the form is loaded follows - we collapse the textblock so the text is no longer visible:

Click HERE for flash demo

Click HERE for demo of different app without loader modifications

The following is the new code in the App.xaml.cs file:

namespace MainShell
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private Shell shell;         /// <summary>
        /// Loads the application.
        /// Bootstrapper is in the Shell.Infrastructure project which
        /// can be shared by multiple solutions.   If you specify a type
        /// as a second parameter (as we do here) versus an IModuleEnumerator
        /// method, the BootStrapper will load all modules in the app
        /// directory (any module it has a reference to).
        /// </summary>
        public App()
        {
            // Display shell with Loading... message
            ShowShell();             // Configure the container and load modules
            BootStrapper bootStrapper = new BootStrapper(CreateShell, GetType());
            bootStrapper.Run();
           
            // Hide the loading message
            shell.tbLoading.Visibility = Visibility.Collapsed;
        }         protected DependencyObject CreateShell(IUnityContainer container)
        {
            container.Resolve<ILogger>()
                .Log("CreateShell (Buildup)", Category.Debug, Priority.Low);             // At this point the bootstrapper has configured the
            // unity container - we can buildup our shell
            container.BuildUp(shell);
            return shell;
        }         /// <summary>
        /// Show the shell immediately - the shell XAML has a Loading...
        /// textblock
        /// </summary>
        protected void ShowShell()
        {
            // We'll have to manually instantiate logger; this will be
            // the only place we tightly couple because we don't have
            // unity container yet.
            ILogger Logger = new TraceToolLogger();
            Logger.Log("Loading Shell", Category.Debug, Priority.Low);             // Instantiate the shell
            shell = new Shell();
            WF.Application.DoEvents(); // prevents black background
            shell.Show();
            WF.Application.DoEvents(); // allows form to completely paint             // This was called before the bootstrapper, the logger
            // won't be in scope so we'll log the entry here
            Logger.Log("Loading Bootstrapper", Category.Debug, Priority.Low);
        }
    }

Source code available HERE - Change Set: 22520

 


Tags: , ,
Categories: CompositeWPF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know