Understanding the change in mindset when switching from WinForms to WPF

October 12, 2012

One of the biggest hurdles I find WinForms developers struggling with when learning WPF and the MVVM design pattern, is understanding the shift in thought process that is used for WPF/MVVM development.

Here’s the best way I can summarize the difference:

  • In WinForms, your forms and UI objects are your application.
  • In WPF/MVVM, the class objects you build are your application, while UI objects are nothing more than a user-friendly interface for interacting with your application objects.

Example

For example, suppose we were asked to make a simple Registration form that takes down a user’s Name, Email Address, and asks them if they want to receive Special Offers or not.

A WinForms developer’s thought process might be to think “I need a Window that contains a TextBox for name, TextBox for email, CheckBox for if they want special offers or not, and a Button to submit the form. When the Submit button is pressed, the data is taken from the UI objects, and saved to the database.”

Winforms Developer's Thought Process

In contrast, a WPF developer’s thought process is “I need a Window that contains a RegistrationForm object. This class needs a string for the Name, a string for the EmailAddress, a boolean property for if they want special offers or not, and a Command to submit the data.”

WPF Developer's Thought Process

But of course WPF doesn’t know how to draw a class of type RegistrationForm, so we’ll have to tell it how to draw the RegistrationForm object using a Template. This template would probably render the Name and EmailAddress properties using TextBoxes, the IsSpecialOffers property with a CheckBox, and provide a Button to run the SaveDataCommand, although that doesn’t have to be the case and is something that can be figured out later.

With WPF, the UI layer and the application layer are so completely separated that you don’t actually need the UI layer at all. If you wanted, you could run your application entirely by test scripts, or through a console window. The actual application layer never needs to reference any UI object to get its data.

Using this concept on a larger scale

In fact, this thought process is used on a much broader scale for the entire WPF/MVVM application.

Want a LoginWindow to come up, and on successful login switch to the MainWindow? No problem, simply start the program with your LoginClass, and on successful Login return the ApplicationClass.

Want to have an application with separate Windows for Products, Orders, and Customers? No problem, create your ApplicationClass to hold a List<T> of available “Window” objects containing the classes representing each “Window”, and include a SelectedWindow property which identifies which window object is currently active.

Of course, WPF needs to know how to draw these class objects, so you’ll need to tell it to use a specific DataTemplate, UserControl, Page, or maybe even Window when rendering these objects.

Summary

This is not meant to be an in-depth look at how WPF is different from WinForms or how to switch from WinForms to WPF, but is more of a brief summary on the change in mindset needed when moving from WinForms to WPF.

With WPF, your application consists of the objects you create, and you use DataTemplates and UI objects to tell WPF how to draw your application components. That’s the opposite of WinForms where you build your application out of UI objects, and then supply them with the data needed.

Once you grasp this key difference, WPF becomes much easier to understand and work with.


What is this “DataContext” you speak of?

July 14, 2012

I frequently see new WPF users confused about what the DataContext is, and how it is used. Hopefully, this can help clarify what the DataContext is, and how it is used.

What is the DataContext?

In WPF, there are two layers to an application: the UI layer and the Data layer.

The Data layer for an application starts out as null, and you can set it using the DataContext property. All UI objects will inherit their DataContext from their parent unless you specify otherwise.

When using the Model-View-ViewModel (MVVM) Design Pattern, the DataContext (Data Layer) is your application, while UI objects, like Buttons, Labels, DataGrids, and even Windows, are all just user-friendly items that allow a user to easily interact with the DataContext, which is your actual application and is typically comprised of ViewModels and Models.

How is it used

Whenever you do a basic binding in WPF, you are binding to the DataContext.

For example, when you write

<Label Name="myLabel" Content="{Binding Path=Name}" />

you are binding to myLabel.DataContext.Name, and not to myLabel.Name.

Other binding properties, such as ElementName or RelativeSource, can be used to tell the binding to lookup the property in something other than the current DataContext.

An Example

Lets start with a regular Window. Without setting the DataContext, the window still displays but there is no data behind it.

<Window x:Name="MyWindow" ...>
   ...
</Window>

Now suppose we set the DataContext to an object of type ClassA in the code-behind when this Window initializes:

public partial class MyWindow: Window
{
    public MyWindow()
    {
       InitializeComponent();
       this.DataContext = new ClassA();
    }
}

Now the data layer behind that the Window is an object of type ClassA.

If ClassA has a property called Name, I could add a Label to the window and bind it to Name property of the DataContext, and whatever value is stored in ClassA.Name would get displayed.

<Window x:Name="MyWindow" ...>
   <Label Content="{Binding Name}" />
</Window>

Now, suppose ClassA has a property called ClassB, and both classes have a property called Name. Here is a block of XAML which illustrates how the DataContext works. It also includes an example of how a control would refer to a property not in its own DataContext.

<!-- DataContext set to ClassA in initialization code -->
<Window x:Name="MyWindow"> 

    <!-- DataContext here is not specified, so it's inherited 
         from its parent's DataContext, which is ClassA -->
    <StackPanel> 

        <!-- DataContext inherited from parent, which is 
             ClassA, so this will display ClassA.Name -->
        <Label Content="{Binding Name}" />

         <!-- DataContext is still ClassA, however we are 
              setting it to ClassA.ClassB with a binding -->
        <StackPanel DataContext="{Binding ClassB}">

            <!-- DataContext inherited from parent, which is 
                 ClassB, so this will display ClassB.Name -->
            <Label Content="{Binding Name}" />

            <!-- DataContext is still ClassB, but we are 
                 binding to the Window's DataContext.Name, 
                 which is ClassA.Name -->
            <Label Content="{Binding 
                       ElementName=MyWindow, 
                       Path=DataContext.Name}" /> 
        </StackPanel>

        <!-- We've left the StackPanel with its DataContext 
             bound to ClassB, so this Label's DataContext 
             is ClassA (inherited from parent StackPanel), 
             and we are binding to ClassA.ClassB.Name -->
        <Label Content="{Binding ClassB.Name}" />
    </StackPanel>
</Window>

As you can see, all the basic bindings look for their value in the data layer (DataContext) of the UI object

Summary

So to summarize, WPF applications have two layers: the UI layer and the Data layer. The data layer for an application starts out as null, and can be set using the DataContext property. UI objects without a DataContext set will inherit their data layer from their parent object. Bindings are used to look up values in the data layer, and display them in the UI layer.

When using the MVVM design pattern, the data layer is your application, while the UI layer just provides a user-friendly way to access the Data layer.


Navigation with MVVM

December 18, 2011

When I first started out with MVVM, I was lost about how you should navigate between pages. I’m a firm believer in using ViewModels to do everything (unless it’s View-specific code), and that the UI is simply a user-friendly interface for your ViewModels. I did not want to create a button on a page that has any kind of code-behind to switch pages, and I didn’t like the idea of my navigation being spread out throughout all the ViewModels.

I finally came to realize the solution was simple: I needed a ViewModel for the Application itself, which contained the application state, such as the CurrentPage.

Here is an example that builds on the Simple MVVM Example.

The ViewModel

Usually I name the ViewModel ApplicationViewModel or ShellViewModel, but you can call it whatever you want. It is the startup page of the application, and it is usually the only page or window object in my project.

It usually contains

    List<ViewModelBase> PageViewModels
    ViewModelBase CurrentPage
    ICommand ChangePageCommand

Here is an example ApplicationViewModel that I would use to go with the Simple MVVM Example.


    public class ApplicationViewModel : ObservableObject
    {
        #region Fields

        private ICommand _changePageCommand;

        private IPageViewModel _currentPageViewModel;
        private List<IPageViewModel> _pageViewModels;

        #endregion

        public ApplicationViewModel()
        {
            // Add available pages
            PageViewModels.Add(new HomeViewModel());
            PageViewModels.Add(new ProductsViewModel());

            // Set starting page
            CurrentPageViewModel = PageViewModels[0];
        }

        #region Properties / Commands

        public ICommand ChangePageCommand
        {
            get
            {
                if (_changePageCommand == null)
                {
                    _changePageCommand = new RelayCommand(
                        p => ChangeViewModel((IPageViewModel)p),
                        p => p is IPageViewModel);
                }

                return _changePageCommand;
            }
        }

        public List<IPageViewModel> PageViewModels
        {
            get
            {
                if (_pageViewModels == null)
                    _pageViewModels = new List<IPageViewModel>();

                return _pageViewModels;
            }
        }

        public IPageViewModel CurrentPageViewModel
        {
            get
            {
                return _currentPageViewModel;
            }
            set
            {
                if (_currentPageViewModel != value)
                {
                    _currentPageViewModel = value;
                    OnPropertyChanged("CurrentPageViewModel");
                }
            }
        }

        #endregion

        #region Methods

        private void ChangeViewModel(IPageViewModel viewModel)
        {
            if (!PageViewModels.Contains(viewModel))
                PageViewModels.Add(viewModel);

            CurrentPageViewModel = PageViewModels
                .FirstOrDefault(vm => vm == viewModel);
        }

        #endregion
    }

This won’t compile right away because I’ve made some changes to it. For one, all my PageViewModels now inherit from an IPageViewModel interface so they can have some common properties, such as a Name.

I also created a new HomeViewModel and HomeView since its hard to demonstrate navigation unless you have at least 2 pages. The HomeViewModel is a blank class that inherits from IPageViewModel, and the HomeView is just a blank UserControl.

In addition, I added an s to ProductsViewModel since it really deals with multiple products, not a single one.

An added advantage to having a ViewModel to control the application state is that it can also be used to handle other application-wide objects, such as Current User, or Error Messages.

The View

I also need an ApplicationView for my ApplicationViewModel. It needs to contain some kind of Navigation that shows the list of PageViewModels, and clicking on a PageViewModel should execute the ChangePage command.

It also needs to contain a control to display the CurrentPage property, and I usually use a ContentControl for that. This allows me to use DataTemplates to tell WPF how to draw each IPageViewModel.

<Window x:Class="SimpleMVVMExample.ApplicationView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SimpleMVVMExample"
        Title="Simple MVVM Example" Height="350" Width="525">

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:HomeViewModel}">
            <local:HomeView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ProductsViewModel}">
            <local:ProductsView />
        </DataTemplate>
    </Window.Resources>

    <DockPanel>
        <Border DockPanel.Dock="Left" BorderBrush="Black" BorderThickness="0,0,1,0">
            <ItemsControl ItemsSource="{Binding PageViewModels}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Button Content="{Binding Name}"
                                Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                                CommandParameter="{Binding }"
                                Margin="2,5"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Border>

        <ContentControl Content="{Binding CurrentPageViewModel}" />
    </DockPanel>
</Window>

In this example, I’m using an ItemsControl to display my PageViewModels. Each item is drawn using a Button, and the Button’s Command property is bound to the ChangePageCommand.

Since the Button’s DataContext is the PageViewModel, I used a RelativeSource binding to find the ChangePageCommand. I know that my Window is the ApplicationView, and it’s DataContext is the ApplicationViewModel, so this binding looks up the VisualTree for the Window tag, and gets bound to Window.DataContext.ChangePageCommand.

Also note that I am putting DataTemplates in Window.Resources to tell WPF how to draw each IPageViewModel. By default, if WPF encounters an object in it’s visual tree that it doesn’t know how to handle, it will draw it using a TextBlock containing the .ToString() method of the object. By defining a DataTemplate, I am telling WPF to use a specific template instead of defaulting to a TextBlock.

If you are continuing from the Simple MVVM Example, I moved the ProductView out of a ResourceDictionary and into a UserControl to make this simpler.

Starting the Example

The last thing to do is change App.xaml to make ApplicationView and ApplicationViewModel our startup, instead of ProductView/ProductViewModel.

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

        ApplicationView app = new ApplicationView();
        ApplicationViewModel context = new ApplicationViewModel();
        app.DataContext = context;
        app.Show();
    }
}

Run the project and you should see something that looks like the images below, which quickly switches the CurrentPage when clicking on the Navigation buttons.

Screenshot of HomeHome

Screenshot of ProductsProducts

Summary

And there you have it. A simple navigation example with MVVM.

You can download the source code for this sample from here.

Once you get more comfortable with WPF, I would recommend looking into using a Messaging System, such as MVVM Light’s Messenger, or Microsoft Prism’s EventAggregator to broadcast ChangePage commands from any ViewModel so you wouldn’t need to find the ApplicationViewModel to execute the ChangePageCommand, however that’s for another day.

<< Back – A Simple MVVM Example
>> Next – Communication between ViewModels


Automatically selecting TextBox Text when Focused

November 5, 2011

Here’s another AttachedProperty from my WPF library that I use a lot. When set on a TextBox, it will select all the text when the TextBox gains keyboard focus.

It is used like this:

<TextBox my:TextBoxHelper.HighlightTextOnFocus="True" />

The actual AttachedProperty defintion looks like this:


public static readonly DependencyProperty HighlightTextOnFocusProperty =
	DependencyProperty.RegisterAttached(
		"HighlightTextOnFocus", typeof(bool), typeof(TextBoxProperties),
		new PropertyMetadata(false, HighlightTextOnFocusPropertyChanged));


[AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetHighlightTextOnFocus(DependencyObject obj)
{
	return (bool)obj.GetValue(HighlightTextOnFocusProperty);
}

public static void SetHighlightTextOnFocus(DependencyObject obj, bool value)
{
	obj.SetValue(HighlightTextOnFocusProperty, value);
}

private static void HighlightTextOnFocusPropertyChanged(DependencyObject obj,
														DependencyPropertyChangedEventArgs e)
{
	var sender = obj as UIElement;
	if (obj != null)
	{
		if ((bool)e.NewValue)
		{
			sender.GotKeyboardFocus += OnKeyboardFocusSelectText;
			sender.PreviewMouseLeftButtonDown += OnMouseLeftButtonDownSetFocus;
		}
		else
		{
			sender.GotKeyboardFocus -= OnKeyboardFocusSelectText;
			sender.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDownSetFocus;
		}
	}
}

private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
{
	var textBox = e.OriginalSource as TextBox;
	if (textBox != null)
	{
		textBox.SelectAll();
	}
}

private static void OnMouseLeftButtonDownSetFocus(object sender, MouseButtonEventArgs e)
{
	TextBox tb = VisualTreeHelpers.FindAncestor((DependencyObject)e.OriginalSource);

	if (tb == null)
		return;

	if (!tb.IsKeyboardFocusWithin)
	{
		tb.Focus();
		e.Handled = true;
	}
}

I particularly like using this in editing forms, so that the user can simply select or tab to a TextBox and start typing the new value, rather then selecting the TextBox, erasing the old value, and then typing the new value. It’s one of those little things that makes an application more user-friendly.


How a VirtualizingStackPanel works

November 5, 2011

A VirtualizingStackPanel is recommended instead of a regular StackPanel when you have a large number of scrollable items.

The reason for this is that a regular scrolling StackPanel will render every single UI element in the list when its loaded, including the ones that are not visible, while a VirtualizingStackPanel will only render the visible UI elements. When you scroll a VirtualizingStackPanel it will re-use the existing elements instead of creating new ones, and simply replaces the DataContext behind them.

For example, if you have an VirtualizingStackPanel with 100,000 items, and only 10 are visible at a time, it will render about 14 items (extra items for a scroll buffer). When you scroll, the DataContext behind those 14 controls gets changed, but the actual controls themselves will never get replaced. In contrast, a regular StackPanel would actually render 100,000 items when it gets loaded, which would dramatically decrease the performance of your application.

To see a VirtualizingStackPanel in action, create one that has a bunch of TextBoxes that are not bound to anything. If you type Text in TextBox #1, and that TextBox.Text is not bound to anything, then the Text will stay in the top TextBox when you scroll the list because the control is getting re-used. If you bind TextBox.Text to a value, then the DataContext will change when you scroll, which will replace the displayed Text.


Navigating WPF’s Visual Tree

October 9, 2011

There are many times when I’ve needed to navigate up or down WPF’s Visual Tree from the code behind to find an object, so I finally decided to put all my visual tree navigation code into a single helper class.

For example, to find controls I can now use the following syntax:

// Search up the VisualTree to find DataGrid 
// containing specific Cell
var parent = VisualTreeHelpers.FindAncestor<DataGrid>(myDataGridCell);

// Search down the VisualTree to find a CheckBox 
// in this DataGridCell
var child = VisualTreeHelpers.FindChild<CheckBox>(myDataGridCell);

// Search up the VisualTree to find a TextBox 
// named SearchTextBox
var searchBox = VisualTreeHelpers.FindAncestor<TextBox>(myDataGridCell, "SeachTextBox");

// Search down the VisualTree to find a Label
// named MyCheckBoxLabel
var specificChild = VisualTreeHelpers.FindChild<Label>(myDataGridCell, "MyCheckBoxLabel");

And here’s the VisualTreeHelpers class

using System.Windows;
using System.Windows.Media;

namespace MyNamespace
{
    public class VisualTreeHelpers
    {
        /// <summary>
        /// Returns the first ancester of specified type
        /// </summary>
        public static T FindAncestor<T>(DependencyObject current)
        where T : DependencyObject
        {
            current = VisualTreeHelper.GetParent(current);

            while (current != null)
            {
                if (current is T)
                {
                    return (T)current;
                }
                current = VisualTreeHelper.GetParent(current);
            };
            return null;
        }

        /// <summary>
        /// Returns a specific ancester of an object
        /// </summary>
        public static T FindAncestor<T>(DependencyObject current, T lookupItem)
        where T : DependencyObject
        {
            while (current != null)
            {
                if (current is T && current == lookupItem)
                {
                    return (T)current;
                }
                current = VisualTreeHelper.GetParent(current);
            };
            return null;
        }

        /// <summary>
        /// Finds an ancestor object by name and type
        /// </summary>
        public static T FindAncestor<T>(DependencyObject current, string parentName)
        where T : DependencyObject
        {
            while (current != null)
            {
                if (!string.IsNullOrEmpty(parentName))
                {
                    var frameworkElement = current as FrameworkElement;
                    if (current is T && frameworkElement != null && frameworkElement.Name == parentName)
                    {
                        return (T)current;
                    }
                }
                else if (current is T)
                {
                    return (T)current;
                }
                current = VisualTreeHelper.GetParent(current);
            };

            return null;

        }

        /// <summary>
        /// Looks for a child control within a parent by name
        /// </summary>
        public static T FindChild<T>(DependencyObject parent, string childName)
        where T : DependencyObject
        {
            // Confirm parent and childName are valid.
            if (parent == null) return null;

            T foundChild = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                // If the child is not of the request child type child
                T childType = child as T;
                if (childType == null)
                {
                    // recursively drill down the tree
                    foundChild = FindChild<T>(child, childName);

                    // If the child is found, break so we do not overwrite the found child.
                    if (foundChild != null) break;
                }
                else if (!string.IsNullOrEmpty(childName))
                {
                    var frameworkElement = child as FrameworkElement;
                    // If the child's name is set for search
                    if (frameworkElement != null && frameworkElement.Name == childName)
                    {
                        // if the child's name is of the request name
                        foundChild = (T)child;
                        break;
                    }
                    else
                    {
                        // recursively drill down the tree
                        foundChild = FindChild<T>(child, childName);

                        // If the child is found, break so we do not overwrite the found child.
                        if (foundChild != null) break;
                    }
                }
                else
                {
                    // child element found.
                    foundChild = (T)child;
                    break;
                }
            }

            return foundChild;
        }

        /// <summary>
        /// Looks for a child control within a parent by type
        /// </summary>
        public static T FindChild<T>(DependencyObject parent)
            where T : DependencyObject
        {
            // Confirm parent is valid.
            if (parent == null) return null;

            T foundChild = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                // If the child is not of the request child type child
                T childType = child as T;
                if (childType == null)
                {
                    // recursively drill down the tree
                    foundChild = FindChild<T>(child);

                    // If the child is found, break so we do not overwrite the found child.
                    if (foundChild != null) break;
                }
                else
                {
                    // child element found.
                    foundChild = (T)child;
                    break;
                }
            }
            return foundChild;
        }    
	}
}

Edit: Finally the link where I got the original code from. I’ve made some modifications to it, but the original code can be found here.


Simplifying PRISM’s EventAggregator

October 9, 2011

I recently started using PRISM’s EventAggregator for messaging in my WPF applications, however I find the syntax confusing, and hard to remember.

Here’s the default syntax for PRISM’s EventAggregator

// Optional: Create Event "Message"
// Needed for multiple parameters, but not for single parameter
// messages. I prefer using one in most cases because I find
// it makes it easier to read the code
public class TickerSymbolSelectedMessage
{
    public string StockSymbol { get; set; }
}

// Create an Event
public class TickerSymbolSelectedEvent : 
    CompositePresentationEvent<TickerSymbolSelectedMessage>{}

// Subscribe to an Event
eventAggregator.GetEvent<ChangeStockEvent>().Subscribe(ShowNews);

public void ShowNews(TickerSymbolSelectedMessage msg)
{
   // Handle Event
}

// Broadcast an Event
eventAggregator.GetEvent<ChangeStockEvent>().Publish(
    new TickerSymbolSelectedMessage{ StockSymbol = “STOCK0” });

There are a few things that irritate me about this syntax:

  • Needing to call GetEvent() all the time before subscribing/publishing
  • Needing a reference to the EventAggregator anywhere I want to use it
  • Needing to create two classes for an Event: the Event itself and the EventMessage (technically this one is optional if you only have one Parameter, but I like to create it anyways because I find it easier to read)

A large portion of the time I am working small apps which usually have a single purpose, so I wrote myself a simple helper class that gets rid of these annoyances. I’m not sure I’d recommend using this in larger apps since it passes all the events over the same channel, but I find it makes my life with small apps much simpler.

Now I just create the EventMessage, and can use some easy Subscribe/Publish calls anywhere in the application. Simple, easy to remember syntax, no need to pass around an EventAggregator object, and all I have to create is my Event Messages.

// Create the Event Message
public class TickerSymbolSelectedMessage
{
    public string StockSymbol { get; set; }
}

// Subscribe to Events
EventSystem.Subscribe<TickerSymbolSelectedMessage>(ShowNews);

public void ShowNews(TickerSymbolSelectedMessage msg)
{
   // Handle Event
}

// Broadcast Events
EventSystem.Publish<TickerSymbolSelectedMessage>(
    new TickerSymbolSelectedMessage{ StockSymbol = “STOCK0”});

And here’s the EventSystem class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Events;

namespace MyNamespace
{
    /// <summary>
    /// Static EventAggregator
    /// </summary>
    public static class EventSystem
    {
        private static IEventAggregator _current;
        public static IEventAggregator Current
        {
            get
            {
                return _current ?? (_current = new EventAggregator());
            }
        }

        private static CompositePresentationEvent<TEvent> GetEvent<TEvent>()
        {
            return Current.GetEvent<CompositePresentationEvent<TEvent>>();
        }

        public static void Publish<TEvent>()
        {
            Publish<TEvent>(default(TEvent));
        }

        public static void Publish<TEvent>(TEvent @event)
        {
            GetEvent<TEvent>().Publish(@event);
        }

        public static SubscriptionToken Subscribe<TEvent>(Action action, ThreadOption threadOption = ThreadOption.PublisherThread, bool keepSubscriberReferenceAlive = false)
        {
            return Subscribe<TEvent>(e => action(), threadOption, keepSubscriberReferenceAlive);
        }

        public static SubscriptionToken Subscribe<TEvent>(Action<TEvent> action, ThreadOption threadOption = ThreadOption.PublisherThread, bool keepSubscriberReferenceAlive = false, Predicate<TEvent> filter = null)
        {
            return GetEvent<TEvent>().Subscribe(action, threadOption, keepSubscriberReferenceAlive, filter);
        }

        public static void Unsubscribe<TEvent>(SubscriptionToken token)
        {
            GetEvent<TEvent>().Unsubscribe(token);
        }        public static void Unsubscribe<TEvent>(Action<TEvent> subscriber)
        {
            GetEvent<TEvent>().Unsubscribe(subscriber);
        }
    }
}

WPF Grid’s Row/Column Count Properties

September 17, 2011

One of my pet peeves with using WPF is that a Grid needs to have it’s Rows and Columns defined. One day I decided I was tired of messing with Row/Column definitions for simple Grids, so sat down to write some AttachedProperties.

Now, instead of writing something like this:


<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
</Grid>

I can write this:


<Grid local:GridHelpers.RowCount="6"
      local:GridHelpers.StarRows="5"
      local:GridHelpers.ColumnCount="4"
      local:GridHelpers.StarColumns="1,3">

</Grid>

I can also use this to draw a Grid with a dynamic number of rows or columns, or where I don’t know the number of rows/columns beforehand such as an ItemsPanelTemplate for an ItemsControl.


<Grid local:GridHelpers.RowCount="{Binding RowCount}"
      local:GridHelpers.ColumnCount="{Binding ColumnCount}" />

GridHelpers Code

Here is the AttachedProperty code:

public class GridHelpers
{
    #region RowCount Property
    
    /// <summary>
    /// Adds the specified number of Rows to RowDefinitions. 
    /// Default Height is Auto
    /// </summary>
    public static readonly DependencyProperty RowCountProperty =
        DependencyProperty.RegisterAttached(
            "RowCount", typeof(int), typeof(GridHelpers),
            new PropertyMetadata(-1, RowCountChanged));
    
    // Get
    public static int GetRowCount(DependencyObject obj)
    {
        return (int)obj.GetValue(RowCountProperty);
    }
    
    // Set
    public static void SetRowCount(DependencyObject obj, int value)
    {
        obj.SetValue(RowCountProperty, value);
    }
    
    // Change Event - Adds the Rows
    public static void RowCountChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || (int)e.NewValue < 0)
            return;
    
        Grid grid = (Grid)obj;
        grid.RowDefinitions.Clear();
    
        for (int i = 0; i < (int)e.NewValue; i++)
            grid.RowDefinitions.Add(
                new RowDefinition() { Height = GridLength.Auto });
    
        SetStarRows(grid);
    }
    
    #endregion
    
    #region ColumnCount Property
    
    /// <summary>
    /// Adds the specified number of Columns to ColumnDefinitions. 
    /// Default Width is Auto
    /// </summary>
    public static readonly DependencyProperty ColumnCountProperty =
        DependencyProperty.RegisterAttached(
            "ColumnCount", typeof(int), typeof(GridHelpers),
            new PropertyMetadata(-1, ColumnCountChanged));
    
    // Get
    public static int GetColumnCount(DependencyObject obj)
    {
        return (int)obj.GetValue(ColumnCountProperty);
    }
    
    // Set
    public static void SetColumnCount(DependencyObject obj, int value)
    {
        obj.SetValue(ColumnCountProperty, value);
    }
    
    // Change Event - Add the Columns
    public static void ColumnCountChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || (int)e.NewValue < 0)
            return;
    
        Grid grid = (Grid)obj;
        grid.ColumnDefinitions.Clear();
    
        for (int i = 0; i < (int)e.NewValue; i++)
            grid.ColumnDefinitions.Add(
                new ColumnDefinition() { Width = GridLength.Auto });
    
        SetStarColumns(grid);
    }
    
    #endregion
    
    #region StarRows Property
    
    /// <summary>
    /// Makes the specified Row's Height equal to Star. 
    /// Can set on multiple Rows
    /// </summary>
    public static readonly DependencyProperty StarRowsProperty =
        DependencyProperty.RegisterAttached(
            "StarRows", typeof(string), typeof(GridHelpers),
            new PropertyMetadata(string.Empty, StarRowsChanged));
    
    // Get
    public static string GetStarRows(DependencyObject obj)
    {
        return (string)obj.GetValue(StarRowsProperty);
    }
    
    // Set
    public static void SetStarRows(DependencyObject obj, string value)
    {
        obj.SetValue(StarRowsProperty, value);
    }
    
    // Change Event - Makes specified Row's Height equal to Star
    public static void StarRowsChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || string.IsNullOrEmpty(e.NewValue.ToString()))
            return;
    
        SetStarRows((Grid)obj);
    }
    
    #endregion
    
    #region StarColumns Property
    
    /// <summary>
    /// Makes the specified Column's Width equal to Star. 
    /// Can set on multiple Columns
    /// </summary>
    public static readonly DependencyProperty StarColumnsProperty =
        DependencyProperty.RegisterAttached(
            "StarColumns", typeof(string), typeof(GridHelpers),
            new PropertyMetadata(string.Empty, StarColumnsChanged));
    
    // Get
    public static string GetStarColumns(DependencyObject obj)
    {
        return (string)obj.GetValue(StarColumnsProperty);
    }
    
    // Set
    public static void SetStarColumns(DependencyObject obj, string value)
    {
        obj.SetValue(StarColumnsProperty, value);
    }
    
    // Change Event - Makes specified Column's Width equal to Star
    public static void StarColumnsChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || string.IsNullOrEmpty(e.NewValue.ToString()))
            return;
    
        SetStarColumns((Grid)obj);
    }
    
    #endregion
    
    private static void SetStarColumns(Grid grid)
    {
        string[] starColumns = 
            GetStarColumns(grid).Split(',');
    
        for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
        {
            if (starColumns.Contains(i.ToString()))
                grid.ColumnDefinitions[i].Width = 
                    new GridLength(1, GridUnitType.Star);
        }
    }
    
    private static void SetStarRows(Grid grid)
    {
        string[] starRows = 
            GetStarRows(grid).Split(',');
    
        for (int i = 0; i < grid.RowDefinitions.Count; i++)
        {
            if (starRows.Contains(i.ToString()))
                grid.RowDefinitions[i].Height = 
                    new GridLength(1, GridUnitType.Star);
        }
    }
}
    

WPF ItemsControl Example

September 17, 2011

I recently wanted to lookup some ItemsControl examples, and was was quite surprised that my good friend Google was unable to find me any good sites.

So here’s some quick examples using an ItemsControl.

Basic ItemsControl

The basic ItemsControl syntax will look like this:

<ItemsControl ItemsSource="{Binding MyCollection}" />

By default, this will create a Vertical StackPanel, then it will loop through each item in MyCollection, add it to a TextBlock, then add that TextBox to the StackPanel.

Here’s a screenshot of the UI objects that get created, identified with Snoop

The ItemTemplate

Quite often you don’t want to simply display an item as a TextBlock, and that’s where the ItemTemplate comes in.

<ItemsControl ItemsSource="{Binding MyCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding }" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

In this example, I simply changed the TextBlock to a Button, so now when it draws the StackPanel it will draw each item using a Button instead of a TextBlock.

A button is a simple example, however your DataTemplates can be (and frequently are) far more complex than a single element.

The ItemsPanelTemplate

Now suppose you want to display your items in something other than a Vertical StackPanel. That’s where the ItemsPanelTemplate comes in.

<ItemsControl ItemsSource="{Binding MyCollection}">
    <!-- ItemsPanelTemplate -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Columns="2" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!-- ItemTemplate -->
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding }" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

In this case, I’ve replaced our StackPanel with a UniformGrid that has 2 Columns

The ItemContainerStyle

The ItemContainerStyle can be used to modify the style of all items in the ItemsControl, however it does not apply this style to the ItemTemplate item, but rather the ContentPresenter that wraps each item (See Snoop Screenshot above)

For example, if I had used a Grid instead of a UniformGrid, and added a Grid.Row and Grid.Column bindings to my Button, you would find that the items do not show up in the correct Grid cell. If I wanted to set each item in the correct Grid cell, I would need to use the ItemContainerStyle to style the ContentPresenter that wraps each item.

<ItemsControl ItemsSource="{Binding MyCollection}">
    <!-- ItemsPanelTemplate -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!-- ItemContainerStyle -->
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Grid.Column" 
                    Value="{Binding ColumnIndex}" />
            <Setter Property="Grid.Row" 
                    Value="{Binding RowIndex}" />
        </Style>
    </ItemsControl.ItemContainerStyle>

    <!-- ItemTemplate -->
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding Name}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Note: For all the screenshots above I was binding to an ObservableCollection of strings, however for the last one I created a custom class that had 3 properties: Name, ColumnIndex, and RowIndex


The Math Converter

August 20, 2011

Quite often I have wanted to adjust a bound value in my XAML by a mathematical formula.

For example, I might want to size a control to 50% of it’s parent’s size. Or I’ll want to position it 30% down and 20% left of a parent panel. Or I might even want to make a control’s width something like 50% of (WindowHeight – 200). Of course, I could always write converters for this, but I got tired of doing that repeatedly so sat down one day to write one big MathConverter.

Using the Math Converter

Using the MathConverter is simple. All you have to do is pass the Converter a math equation as the ConverterParameter, substituting @VALUE for your bound value. The equation can consist of numbers, basic operators (+, -, *, /, %), parentheses, and @VALUE.

For example, if you wanted a control whose height was 50% of the current Window Size, you would create a binding that looked like this:

Height="{Binding ElementName=RootWindow, Path=ActualHeight,
                 Converter={StaticResource MathConverter},
                 ConverterParameter=@VALUE/2}"

Or if you wanted to make the control’s width equal to 30% of (WindowWidth – 200) your binding might look like this:

Width="{Binding ElementName=RootWindow, Path=ActualWidth,
                Converter={StaticResource MathConverter},
                ConverterParameter=((@VALUE-200)*.3)}"

The Math Converter

Here’s the actual converter code.

It takes the ConverterParameter, substitutes the bound value for @VALUE, then starts reading the equation from left-to-right. If it encounters an operator, it performs the specified operation on the previous number and the next number in the list. If it encounters a parentheses, it handles the equation inside the group first, then replaces the grouped equation in the string with the result of the grouped equation. Any character it finds that is not a number, operator, or parentheses throws an exception.

// Does a math equation on the bound value.
// Use @VALUE in your mathEquation as a substitute for bound value
// Operator order is parenthesis first, then Left-To-Right (no operator precedence)
public class MathConverter : IValueConverter
{
    private static readonly char[] _allOperators = new[] { '+', '-', '*', '/', '%', '(', ')' };

    private static readonly List<string> _grouping = new List<string> { "(", ")" };
    private static readonly List<string> _operators = new List<string> { "+", "-", "*", "/", "%" };

    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Parse value into equation and remove spaces
        var mathEquation = parameter as string;
        mathEquation = mathEquation.Replace(" ", "");
        mathEquation = mathEquation.Replace("@VALUE", value.ToString());

        // Validate values and get list of numbers in equation
        var numbers = new List<double>();
        double tmp;

        foreach (string s in mathEquation.Split(_allOperators))
        {
            if (s != string.Empty)
            {
                if (double.TryParse(s, out tmp))
                {
                    numbers.Add(tmp);
                }
                else
                {
                    // Handle Error - Some non-numeric, operator, or grouping character found in string
                    throw new InvalidCastException();
                }
            }
        }

        // Begin parsing method
        EvaluateMathString(ref mathEquation, ref numbers, 0);

        // After parsing the numbers list should only have one value - the total
        return numbers[0];
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion

    // Evaluates a mathematical string and keeps track of the results in a List<double> of numbers
    private void EvaluateMathString(ref string mathEquation, ref List<double> numbers, int index)
    {
        // Loop through each mathemtaical token in the equation
        string token = GetNextToken(mathEquation);

        while (token != string.Empty)
        {
            // Remove token from mathEquation
            mathEquation = mathEquation.Remove(0, token.Length);

            // If token is a grouping character, it affects program flow
            if (_grouping.Contains(token))
            {
                switch (token)
                {
                    case "(":
                        EvaluateMathString(ref mathEquation, ref numbers, index);
                        break;

                    case ")":
                        return;
                }
            }

            // If token is an operator, do requested operation
            if (_operators.Contains(token))
            {
                // If next token after operator is a parenthesis, call method recursively
                string nextToken = GetNextToken(mathEquation);
                if (nextToken == "(")
                {
                    EvaluateMathString(ref mathEquation, ref numbers, index + 1);
                }

                // Verify that enough numbers exist in the List<double> to complete the operation
                // and that the next token is either the number expected, or it was a ( meaning
                // that this was called recursively and that the number changed
                if (numbers.Count > (index + 1) &&
                    (double.Parse(nextToken) == numbers[index + 1] || nextToken == "("))
                {
                    switch (token)
                    {
                        case "+":
                            numbers[index] = numbers[index] + numbers[index + 1];
                            break;
                        case "-":
                            numbers[index] = numbers[index] - numbers[index + 1];
                            break;
                        case "*":
                            numbers[index] = numbers[index] * numbers[index + 1];
                            break;
                        case "/":
                            numbers[index] = numbers[index] / numbers[index + 1];
                            break;
                        case "%":
                            numbers[index] = numbers[index] % numbers[index + 1];
                            break;
                    }
                    numbers.RemoveAt(index + 1);
                }
                else
                {
                    // Handle Error - Next token is not the expected number
                    throw new FormatException("Next token is not the expected number");
                }
            }

            token = GetNextToken(mathEquation);
        }
    }

    // Gets the next mathematical token in the equation
    private string GetNextToken(string mathEquation)
    {
        // If we're at the end of the equation, return string.empty
        if (mathEquation == string.Empty)
        {
            return string.Empty;
        }

        // Get next operator or numeric value in equation and return it
        string tmp = "";
        foreach (char c in mathEquation)
        {
            if (_allOperators.Contains(c))
            {
                return (tmp == "" ? c.ToString() : tmp);
            }
            else
            {
                tmp += c;
            }
        }

        return tmp;
    }
}

One day I plan on expanding this further to use an IMultiValueConverter that accepts multiple bindings, but I haven’t had a need for that yet so it hasn’t gotten done.