Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Building an Extensible Application with MEF, WPF, and MVVM

, 15 Nov 2009 LGPL3
An article for anyone interested in how to build an extensible application using WPF and the Model-View-ViewModel pattern.
SoapBox.Demo.Setup.zip
SoapBox.Demo.Setup
setup.exe
SoapBox.Demo.Setup.msi
SoapBoxCoreWithDemo.zip
SoapBoxCoreWithDemo
AvalonDock
AvalonDock
AvalonDock.snk
doc
AvalonDock.shfb
Help
LastBuild.log
DrWPF
GreyableImage
Properties
Settings.settings
Resources
DocumentHS.png
images
Aero
AeroDockBottom.png
AeroDockBottomHover.png
AeroDockLeft.png
AeroDockLeftHover.png
AeroDockPane.png
AeroDockPaneBottom.png
AeroDockPaneInto.png
AeroDockPaneLeft.png
AeroDockPaneRight.png
AeroDockPaneTop.png
AeroDockRight.png
AeroDockRightHover.png
AeroDockTop.png
AeroDockTopHover.png
Classic
PinAutoHide.png
PinAutoHideSelected.png
PinClose.png
PinCloseSelected.png
PinMenu.png
PinMenuSelected.png
DockBottom.PNG
DockLeft.PNG
DockPane.PNG
DockRight.PNG
DockTop.PNG
HTabGroup.png
Locked.png
PinAutoHide.png
PinClose.png
PinDocMenu.png
PinMenu.png
Thumbs.db
VTabGroup.png
themes
bin
NLog
src
NLog.snk
NLog
Conditions
Config
DotNet
Filters
Internal
FileAppenders
NetworkSenders
Win32
LayoutRenderers
Layouts
Mono
NLog.vs2003.csdproj
Targets
Compound
Wrappers
Unix
Web
Win32
LayoutRenderers
Targets
Physics2D
AdvanceMath
Design
Geometry2D
IO
Properties
Physics2DDotNet
Collections
DataTypes
Detectors
Ignorers
Joints
Physics2DDotNet.csproj.user
PhysicsLogics
Properties
Shapes
Solvers
References
System.ComponentModel.Composition.dll
Release
SoapBox
CodeSnippets
PropArgs.snippet
PropName.snippet
SoapBox.Core
SoapBox.Core.Arena
Arena
ArenaBodies
Physics
Utility
Properties
SoapBox.Core.Arena.csproj.user
SoapBox.Core.Contracts
App
Startup
Conditions
Gui
Controls
Layout
MenuItem
Options
StatusBar
StatusBarButton
StatusBarLabel
StatusBarRadioButton
StatusBarSeparator
StatusBarToggleButton
ToolBar
ToolBarItem
ToolBarButton
ToolBarLabel
ToolBarRadioButton
ToolBarSeparator
ToolBarToggleButton
ViewModel
Properties
Services
ExtensionService
LoggingService
Utilities
SoapBox.Core.Host
Properties
app.manifest
Settings.settings
SoapBox.Core.Layout
Layout
Properties
SoapBox.Core.Logging
Properties
Services
LoggingService
SoapBox.Core.Options
Options
Properties
Resources
cog.png
Workbench
MainMenu
SoapBox.Core.Workbench
Properties
Settings.settings
Resources
SoapBox.Core.Workbench.csproj.user
Workbench
MainMenu
SoapBox.Demo
SoapBox.Demo.HighScores
Layout
Pads
PinBall
Properties
Settings.settings
Resources
Workbench
MainMenu
SoapBox.Demo.PinBall
App
StartupCommands
star.png
Arena
ArenaBodies
Pin
PinBall
PinBallBonus
PinBallBottomBumper
PinBallBottomRamp
PinBallFlipper
PinBallFlipperMount
PinBallKicker
PinBallLauncher
PinBallLevel
PinBallPartition
PinBallReturnRamp
PinBallRoundedTop
PinBallSensor
PinBallStop
PinBallTableEdge
PinBallTarget
Options
Pads
Properties
Settings.settings
Resources
Sounds
beat1.wav
beat2.wav
bonus_fast.wav
brooomm.wav
doodoodoodoo.wav
driiinng2.wav
flip.wav
rattata_single.wav
tack.wav
tick.wav
time.wav
SoapBox.Demo.PinBall.csproj.user
Sound
Workbench
MainMenu
StatusBar
SoapBox.Demo.Setup
Debug
SoapBox.Demo.Setup.vdproj
// 
// Copyright (c) 2004-2006 Jaroslaw Kowalski <jaak@jkowalski.net>
// 
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
// * Redistributions of source code must retain the above copyright notice, 
//   this list of conditions and the following disclaimer. 
// 
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution. 
// 
// * Neither the name of Jaroslaw Kowalski nor the names of its 
//   contributors may be used to endorse or promote products derived from this
//   software without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
// THE POSSIBILITY OF SUCH DAMAGE.
// 

using System;
using System.Collections;
using System.Xml;
using System.Globalization;
using System.Reflection;

using NLog;
using NLog.Internal;
using NLog.Targets;

namespace NLog.Config
{
    /// <summary>
    /// Keeps logging configuration and provides simple API
    /// to modify it.
    /// </summary>
    public class LoggingConfiguration
    {
        internal TargetDictionary _targets = new TargetDictionary();
        internal TargetCollection _aliveTargets = new TargetCollection();
        private LoggingRuleCollection _loggingRules = new LoggingRuleCollection();

        /// <summary>
        /// Creates new instance of LoggingConfiguration object.
        /// </summary>
        public LoggingConfiguration(){}

        /// <summary>
        /// Registers the specified target object under a given name.
        /// </summary>
        /// <param name="name">Name of the target.</param>
        /// <param name="target">The target object.</param>
        public void AddTarget(string name, Target target)
        {
            if (name == null)
                throw new ArgumentException("name", "Target name cannot be null");
            InternalLogger.Debug("Registering target {0}: {1}", name, target.GetType().FullName);
            _targets[name.ToLower(CultureInfo.InvariantCulture)] = target;
        }

        /// <summary>
        /// Removes the specified named target.
        /// </summary>
        /// <param name="name">Name of the target.</param>
        public void RemoveTarget(string name)
        {
            _targets.Remove(name.ToLower(CultureInfo.InvariantCulture));
        }

        /// <summary>
        /// Finds the target with the specified name.
        /// </summary>
        /// <param name="name">The name of the target to be found.</param>
        /// <returns>Found target or <see langword="null" /> when the target is not found.</returns>
        public Target FindTargetByName(string name)
        {
            return _targets[name.ToLower(CultureInfo.InvariantCulture)];
        }

        /// <summary>
        /// The collection of logging rules
        /// </summary>
        public LoggingRuleCollection LoggingRules
        {
            get { return _loggingRules; }
        }

        /// <summary>
        /// A collection of file names which should be watched for changes by NLog.
        /// </summary>
        public virtual ICollection FileNamesToWatch
        {
            get { return null; }
        }

        /// <summary>
        /// Called by LogManager when one of the log configuration files changes.
        /// </summary>
        /// <returns>A new instance of <see cref="LoggingConfiguration" /> that represents the updated configuration.</returns>
        public virtual LoggingConfiguration Reload()
        {
            return this;
        }

        
        /// <summary>
        /// Flushes any pending log messages on all appenders.
        /// </summary>
        internal void FlushAllTargets(TimeSpan timeout)
        {
            foreach (Target target in _targets.Values)
            {
                try
                {
                    target.Flush(timeout);
                
                }
                catch (Exception ex)
                {
                    InternalLogger.Error("Error while flushing target: {0} {1}", target.Name, ex); 
                }
            }
        }

        internal void InitializeAll()
        {
            foreach (LoggingRule r in LoggingRules)
            {
                foreach (Target t in r.Targets)
                {
                    if (!_aliveTargets.Contains(t))
                        _aliveTargets.Add(t);
                }
            }

            foreach (Target target in _aliveTargets)
            {
                try
                {
                    target.Initialize();
                
                }
                catch (Exception ex)
                {
                    InternalLogger.Error("Error while initializing target: {0} {1}", target.Name, ex); 
                }
            }
        }

        /// <summary>
        /// Returns a collection of named targets specified in the configuration.
        /// </summary>
        /// <returns>A <see cref="TargetCollection"/> object that contains a list of named targets.</returns>
        /// <remarks>
        /// Unnamed targets (such as those wrapped by other targets) are not returned.
        /// </remarks>
        public TargetCollection GetConfiguredNamedTargets()
        {
            TargetCollection tc = new TargetCollection();
            foreach (Target t in _targets.Values)
            {
                tc.Add(t);
            }
            return tc;
        }


        /// <summary>
        /// Closes all targets and releases any unmanaged resources.
        /// </summary>
        public void Close()
        {
            InternalLogger.Debug("Closing logging configuration...");
            foreach (Target target in _aliveTargets)
            {
                try
                {
                    InternalLogger.Debug("Closing target {1} ({0})", target.Name, target.GetType().FullName);
                    target.Close();
                }
                catch (Exception ex)
                {
                    InternalLogger.Error("Error while closing target: {0} {1}", target.Name, ex); 
                }
            }
        }
    }
}

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 GNU Lesser General Public License (LGPLv3)

Share

About the Author

Scott Whitlock
Engineer
Canada Canada
By day I'm a Professional Engineer, doing .NET, VB6, SQL Server, and Automation (Ladder Logic, etc.) programming.
 
On weekends I write and maintain an open source extensible application framework called SoapBox Core.
 
In the evenings I provide front line technical support for moms4mom.com and I help out with administrative tasks (like formatting stuff). I also pitch in as a moderator from time to time.
 
You can follow me on twitter.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150331.1 | Last Updated 15 Nov 2009
Article Copyright 2009 by Scott Whitlock
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid