Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Introducing MixModes Synergy 2010

0.00/5 (No votes)
31 Oct 2011 1  
Introducing MixModes Synergy 2010

For the past few months, I have been engaged in the development of Windows Presentation Foundation (WPF) based SDK called MixModes Synergy 2010 in my company. MixModes Inc. Synergy is a WPF toolkit that unleashes the power of WPF via simpler programming constructs and provides out of the box custom controls that allows Rapid Application Development of line of business applications. MixModes Synergy 2010 can be downloaded here.

This SDK will be ongoing development that MixModes Inc. will pursue to provide best possible support for WPF and Silverlight development. Some of the features in version 1.0 include:

  • Base framework for WPF development
  • Easy and type-safe adoption of Model-View-ViewModel pattern
  • Custom visual adorners
  • Logical behaviors
  • Out of the box custom controls

MixModes Synergy 2010 is free for all uses and is MixModes Inc.’s initiative to contribute to the developer community. In this blog, I will uncover the solutions Synergy provides in each of the above categories.

Base Framework for WPF Development

Commanding

CommandBase class provides a flexible implementation for custom commands. This class works on an Action<object> instance for command invocation and an optional Predicate<object> for command execution evaluation. If predicate is not specified, it is assumed that command can execute at any time. Also, CommandBase exposes CanExecuteChanged event that is registered with CommandManager which then re-queries validity of command execution based on user interaction with the application.

Simply speaking, one can instantiate a command base class as follows:

CommandBase myCommand = new CommandBase(arg=>DoFoo(arg), arg=> CanFoo(arg));

FrameworkElement Extensions

FrameworkElementExtensions class contains a list of extension methods for FrameworkElement instances that help in finding logical and visual parents of specified type, clearing adorner layer for element, enforcing element size and displaying tooltips very easily.

Window Enhancements

CustomWindow class provides a fast way to create a custom window by just declaring a template for custom window and specifying the named parts for window controls.

Dialog Window Enhancements

DialogWindow provides a true dialog box look and feel for modal dialogs by setting appropriate window style on the dialogs. This fixes WPF bugs around inability of dialog windows to hide control box.

DependencyProperty Change Detection

ObservableDependencyProperty class can monitor change in a dependency property of a dependency object without the need for separate events. To monitor changes in a dependency property for a dependency object, one needs to supply a callback delegate of type DependencyPropertyChangedEventHandler. The following code illustrates usage of ObservableDependencyProperty:

ObservableDependencyProperty descriptor = new ObservableDependencyProperty(    
typeof(string), 
TextBox.TextProperty,     
OnTextChanged);
  
descriptor.AddValueChanged(myTextBox);
  
void OnTextChanged(object sender, DependencyPropertyChangedEventArgs e)    
{     
    TextBox changedBox = sender as TextBox;     
    string oldValue = e.OldValue as string;     
    string newValue = e.NewValue as string;     
}

If monitoring of a specific dependency property on a list of elements is required, ObservableDependencyPropertyCollection provides the necessary plumbing for ease of tracking changes.

_dockPaneStateMonitorList = 
   new ObservableDependencyPropertyCollection<DockPane>(DockPane.DockPaneStateProperty);    
_dockPaneStateMonitorList.DependencyPropertyChanged += OnDockPaneStateChanged;     
    
_dockPaneStateMonitorList.Add(myDockPane);     
    
private void OnDockPaneStateChanged(object sender, DependencyPropertyChangedEventArgs e)     
{     
      DockPane pane = sender as DockPane;     
      DockPaneState state = (DockPaneState)e.NewValue;     
}

Easy and Type-safe Adoption of Model-View-ViewModel Pattern

ViewModelBase class provides a type safe RaisePropertyChanged method for derived classes and hence provides compile time property name checks. Rather than passing in a string as the property name, derived classes raise PropertyChanged event as follows:

RaisePropertyChanged(x=>this.MyProperty);

Custom Visual Adorners

MixModes Synergy allows for visual creation of adorners. In fact, any visual can be transformed into an adorner with practically few lines of code. All this magic is done through the use of ContentAdornerBase class that makes creating visual adorners no different than creating a user control. It just takes a few steps to create a visual adorner:

  • Create a visual resource in your resource dictionary – This can be done using Blend designer. Ensure that x:Shared is set to False on the resource. This means that anytime you host the resource on multiple elements, a copy of visual tree shall be created preventing duplicate parenting issues.
  • If the resource dictionary is different from default application resource dictionary, place a link in the merged dictionary section of default application dictionary to load it.
  • Derive a class from ContentAdornerBase; load and pass in the visual resource from resource dictionary and pass it onto the base constructor.
  • Add the derivative class to adorned element’s adorner layer.

As an example, let’s assume that you want to create a reusable adorner that helps resize adorned element. Following the steps above, you could define a resource in the resource dictionary ResizableAdorner.xaml:

<Grid x:Key="ResizableAdorner" x:Shared="False">    
:     
</Grid>

Link ResizableAdorner.xml to your application resource dictionary as one of the merged dictionary:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">     
  <ResourceDictionary.MergedDictionaries>     
    <ResourceDictionary Source="ResizableAdorner.xaml" />     
    :     
  </ResourceDictionary.MergedDictionaries>     
</ResourceDictionary>

Create a class ResizingAdorner deriving from ContentAdornerBase as follows:

/// <summary>    
/// Resizing adorner     
/// </summary>     
internal class ResizingAdorner : ContentAdornerBase     
{     
    /// <summary>     
    /// Initializes a new instance of the <see cref="ResizingAdorner"/> class.     
    /// </summary>     
    /// <param name="adornedElement">The element to bind the adorner to</param>     
    /// <exception cref="ArgumentNullException">adornedElement is null</exception>     
    internal ResizingAdorner(UIElement adornedElement)     
      : base(adornedElement, Application.Current.Resources[“ResizableAdorner”] as FrameworkElement)
    {     
      AttachNamedParts();     
    }     
    
    /// <summary>     
    /// Attaches the named parts     
    /// </summary>     
    private void AttachNamedParts()     
    {     
      // Use FindElement<T> to find named parts and attach behavior here     
    }    
}

Finally, just place the adorner to adorned element’s adorner layer:

AdornerLayer layer = AdornerLayer.GetAdornerLayer(someFrameworkElement);    
if (layer != null)     
{     
    layer.Add(new ResizingAdorner(someFrameworkElement));     
}

That’s all the steps you need to create a visual adorner!

Logical Behaviors

Logical behavior is a new concept introduced by MixModes Synergy that decouples behavior from its visual parent. The idea is to define visual behavior in control templates that can then bind to an ancestor visual element or a template parent in attaching the behavior. To create a logical behavior, follow the steps given below:

  • Derive a behavior from LogicalParentBehavior<T> class and supply the logical parent as the generic parameter during derived class definition.
  • In the overridden OnAttached method, call base.OnAttached and then access LogicalParent property of the base class to access the logical parent to attach behavior.
  • In the XAML, just declare behavior in the usual fashion to any visual element.

Out of the Box Custom Controls

MixModes Synergy provides out of the box custom controls that are easily consumable from your WPF based applications. All the controls released as part of MixModes Synergy 2010 SDK are completely look-less and can be custom themed on top of the standard themes that ships as part of the SDK. MixModes will release additional custom controls on a regular basis to enrich Synergy and provide out of the box support in the development for line of business applications.

One major control release in the current release is the window docking solution similar to docking windows in Microsoft Visual Studio. Using docking window control is very simple. In your XAML just add the WindowManager control:

<visualFx:WindowsManager x:Name="WindowsManager"/>

WindowsManager as the name suggests is the primary manager for Windows in docking solution. Each dockable window is an instance of DockPane class which is a derivative of HeaderedContentControl. Hence, DockPane instance can have a Header (which serves as the title of the DockPane) and a Content (which serves as the content of the DockPane).

DockPane can be added in many different ways to the WindowsManager:

  • As pinned window – via WindowsManager.AddPinnedWindow(DockPane, Dock) method
  • As auto hidden window – via WindowsManager.AddAutoHideWindow(DockPane, Dock) method
  • As floating window – via WindowsManager.AddFloatingWindow(DockPane) method
  • As a document in the main document area – via WindowsManager.DocumentContainer.AddDocument(DockPane) method

DocumentContainer is the component that organizes documents within WindowsManager (this excludes pinned, auto-hidden and floating windows since they are not considered documents).

MixModes Synergy 2010 also provides window state serialization and deserialization for your application environment to preserve and load the window environment of any complexity.

Out of the box, Synergy provides XML serialization of window states through XmlWindowsManagerSerializer and XmlWindowsManagerDeserializer classes. Custom serialization is supported via specialization of base classes WindowsManagerSerializer and WindowsManagerDeserializer respectively.

XML serialization of WindowsManager using XmlWindowsManagerSerializer requires two pieces of information during construction:

  • DockPane writer – An Action<XmlElement, DockPane> instance that can write additional metadata about a DockPane to the XmlElement.
  • Document writer – A Func<DocumentContent, string> instance that takes in a DocumentContent and returns a string representation of the content. Note: DocumentContent.DockPane property returns the associated DockPane, however the Header and Content properties of DockPane are set to null. To access Header and Content property, use the Header and Content properties of DocumentContent instance directly.

Once XmlWindowsManagerSerializer instance is created, a call to Serialize(Stream, WindowsManager) method serializes WindowsManager to the stream.

Similar to serialization process, deserialization process requires an instance of Action<DockPane, string> within the constructor of XmlWindowsManagerDeserializer to de-serialize a DockPane from previously saved string representation. Deserialization does not require additional Action to realize DocumentContent since DocumentContent is inherently a serialization wrapper for DockPane.

Once XmlWindowsManagerDeserializer instance is created, a call to Deserialize(Stream, WindowsManager) deserializes the WindowsManager to previously saved state.

Summary

MixModes Synergy 2010 is an ongoing project and several additions will be made to the SDK based on customer requests. Everyone is encouraged to download and play with the SDK and please send me your questions and suggestions here. Thank you all very much.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here