Archive for July 2012

WPF MenuItem as a RadioButton

It seems that there is not a MenuItem that works as a RadioButton that allows only a single selection that is in WPF. So I set off to figure out the best way to do this in WPF.

So let me go ahead and put the final solution right here on top. Then I will walk you through how I arrived at this solution. I researched a lot of solutions and none of them were this solution. I had to figure this one out myself  and I am glad I did because this one is the shortest and sweetest solution yet.

Here is a project showing how to do this with two examples, one directly in the MainWindow.xaml and one as its own class.

MenuItemWithRadioButtonExample.zip

Here is the code for creating a class that just works as a MenuItem with a RadioButton.

<MenuItem x:Class="MenuItemWithRadioButtonExample.MenuItemWithRadioButton"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Header="RadioButton Menu" >
    <MenuItem.Resources>
        <RadioButton x:Key="RadioButtonResource" x:Shared="false" HorizontalAlignment="Center"
                     GroupName="MenuItemRadio" IsHitTestVisible="False"/>
    </MenuItem.Resources>
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Icon" Value="{DynamicResource RadioButtonResource}"/>
            <EventSetter Event="Click" Handler="MenuItemWithRadioButtons_Click" />
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

Then you need to add the MenuItemWithRadioButtons_Click event method to your code-behind as well.

private void MenuItemWithRadioButtons_Click(object sender, System.Windows.RoutedEventArgs e)
{
    MenuItem mi = sender as MenuItem;
    if (mi != null)
    {
        RadioButton rb = mi.Icon as RadioButton;
        if (rb != null)
        {
            rb.IsChecked = true;
        }
    }
}

Note: Since this even code involves the View only, this doesn’t break MVVM. With MVVM it is allowed to put code in the code-behind as long as it is code only for the View.

This works quite well and I am quite happy with it. Here is how it looks

Attempt 1 – A RadioButton in MenuItem.ItemsTemplate

Result = Failed!

I changed the MenuItem.ItemsTemplate, as follows.

<MenuItem.ItemTemplate>
    <DataTemplate>
        <RadioButton Content="{Binding}" GroupName="Group" />
    </DataTemplate>
</MenuItem.ItemTemplate>

This almost worked, but it wasn’t quite right. It turns out that anything in the DataTemplate is actually boxed inside a MenuItem, so it left a space. Look at this screen shot.

Notice there is a square space on the left, then a slight separator, then our RadioButton. We need the toggle to be in that empty box, and only the text to be on the right. Also clicking on the empty box doesn’t click the RadioButton.

So I need to figure out how to make it not be boxed in a MenuItem. It might be possible to find a way to make the DataTemplate not be boxed in a MenuItem, but I researched this and decided it wasn’t the best way to go.

Attempt 2 – A RadioButton in MenuItem.ItemContainerStyle

Result = Failed!

In my second attempt, I attempted to change the ItemContainerStyle.

<MenuItem.ItemContainerStyle>
    <Style TargetType="MenuItem">
        <Setter Property="Icon">
            <Setter.Value>
                <RadioButton HorizontalAlignment="Center" GroupName="MenuItemRadio" />
            </Setter.Value>
        </Setter>
    </Style>
</MenuItem.ItemContainerStyle>

This didn’t work either. Look at this screen shot.

It seems that only one instance of the RadioButton was created on so only the last item it was applied to actual showed it.

It had a second issue in that the RadioButton didn’t actually have any content. This might be a problem if you are hoping to use the Content in a click event. It seems that both MenuItem.Header and RadioButton.Content should be the same value, but only the MenuItem.Header should display.

The third issue was that the RadioButton is only toggled when clicking directly on the RadioButton, but not when clicking on the text or “Header” portion of the MenuItem.

The fourth issue is that when clicking the RadioButton the menu stays open even if StayOpenOnClick=”false” is set.

Attempt 3 – An unshared RadioButton in Resources used by MenuItem.ItemsTemplate (Success)

While it didn’t work the first time, this method had promise. Step two got me close, but left me with three problems to solve.

  1. I needed to figure out a way to not have the MenuItem elements share the RadioButton and that didn’t take long to research and resolve. I just needed to declare the RadioButton outside the Style and then use a StaticResource to bind to it.
  2. I needed to add an event to have the MenuItem click pass the click on to the RadioButton. That was easy enough.
  3. I needed to make it so the Menu would close when clicking directly on the RadioButton. I actually just set IsHitTestVisible=”false” on the RadioButton, because we already made just clicking the MenuItem work in problem 2.
  4. I had to change the RadioButton’s Horizontal Alignment to Center to make it look best.

So here is a screenshot so you can see it looks just how you want.

Check out the Xaml and event method as well as the example project at the top of this page.

Note: If you need to make the MenuItem.Header and RadioButton.Content share the same value, then do this:

<MenuItem x:Class="MenuItemWithRadioButtonExample.MenuItemWithRadioButton"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Header="RadioButton Menu" >
    <MenuItem.Resources>
        <RadioButton x:Key="RadioButtonResource" x:Shared="false" HorizontalAlignment="Center" 
                     GroupName="MenuItemRadio" IsHitTestVisible="False">
            <RadioButton.Content>
                <Label Content="{Binding Path=Header, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                       Visibility="Collapsed"/>
            </RadioButton.Content>
        </RadioButton>
    </MenuItem.Resources>
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Icon" Value="{DynamicResource RadioButtonResource}"/>
            <EventSetter Event="Click" Handler="MenuItemWithRadioButtons_Click" />
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

Notice that Visibility=”Collapsed” is set, as we don’t need both the MenuItem.Header and the RadioButton.Content to display. I thought I needed this, but it turned out I didn’t. Still, I thought I would share it anyway.

An actual in-production MVVM architecture

Actual MVVM Design

So the last project where I implemented MVVM that is in production for an enterprise product, the design pattern actually grew to included more than just the three items: Model, View, ViewModel.

Instead it looked like the image you see to the right.

The arrows indicate access.

  • Controller – Has access to all other objects. Basically the controller is created and it loads the first Views and ViewModels and assigns the DataContext of the Views.
  • View –  The view is only consumed by the controller (and dynamically so the controller doesn’t actually reference the View project or dll). Since the view is completely independent it can be replaced any time. The View is only connected to the ViewModel through binding when the controller assigns a ViewModel to the DataContext of a View.
  • ViewModel – An adapter layer on top of the model and business that also implements the necessary objects that are expected in the View’s bindings. The ViewModel communicates with the controller in order to tell it to change screens/switch to a new view. It is important in this design to note that the ViewModel never references the View and is completely independent of the View, which allows it to be applied to any View.
  • Business – The code that actual does the work. It only needs access to the Model but both the Controller and ViewModel have access to use it. However, the Controller seldom uses it but the ViewModel heavily uses it.
  • Model – Data objects. It doesn’t know about anything else, but the Controller, Business, and ViewModel all know about the Model.

How this design formed

Originally the MVVM pattern was used and the project started as a single project, with a separate folder and namespace for Model-View-ViewModel times.

As the application progressed, this design was created as separation of concerns were applied to each layer and as items were broken out into separate projects/dlls.

Why the Controller became a separate layer

Initially it seems that the View or the ViewModel (either) could handle being the Controller. However, we found that neither the View or the ViewModel acting as the Controller was a good idea for a couple of reasons. First, if the View or the ViewModel were also the Controller then they became dependent on too many items. It became clear quickly that the ViewModel was a better choice of the two and so it was chosen at first. However, with references to the View available to the ViewModel, developers began to cheat and couple the View to the ViewModel, until the ViewModel could not build without that exact View and the View was supposed to be dynamic and interchangeable.

So to keep the View decoupled from the ViewModel and visa-versa, a separate Controller project was created and no reference between the View or ViewModel was allowed.

Note: Actually the Business and Controller layers are in the same dll.

Why the Business layer was separated from the ViewModel

Initially the Business layer and the ViewModel layer were the same layer. Some of the business existed directly in the ViewModel and some were in separate classes. It quickly became apparent that the ViewModels were 1) getting too large, and 2) breaking the single responsibility principle. It became apparent that in order to maintain small class files and the single responsibility principle that the Business needed to exist outside of the ViewModel and the ViewModel would simply call the a single Business object or method when needed.

Other mistakes

Initially the Controller was a single class, then we realized that it was doing about ten things, and was over 1000 lines. Oops. It was refactored into separate objects, some of which actually turned out to belong in the business layer.  So it appeared that we allowed the business layer to bleed into the controller. As the file was analyzed it was clear that a certain amount of methods and properties were only for a particular use and so these were extracted to a separate class. This was actually repeated multiple times for different uses, after which, the controller returned to just being a controller and it was a smaller easy to maintain class.

Future architecture changes

As the product continued to grow, other changes are seen as necessary even though they haven’t yet been implemented.

Separation of the Controller from the Business layer

A few of the business objects were for the Controller only and the rest of the business objects are for the ViewModel only. Since the Controller and Business layers are still in the same dll, this doesn’t yet matter. However, it was becoming clear as the project grew that the Controller has its business and the ViewModel/functionality had it Business and there is little overlap if any. It is likely that the Controller and Business layer will see a separation and decoupling where the Controller no longer references the Business layer and the business classes used by the Controller is just part of the Controller.

View communication with the DataContext without binding

There arose instances where binding was not supported or did not exist. In many cases we used attached properties or an inherited object and added the missing bindings, however, in some instances this didn’t make sense. What if the View needed to send a message to the DataContext or pass and event to the code behind and neither inheriting the object to add the binding or using an attached property made sense. What made sense was an interface.

I recently posted an article on Creating an Interface for data binding in Views with WPF. Imagine a new layer that exists between the View and the ViewModel called IViewModel. Both the View and the ViewModel reference it and they still don’t reference each other. An interface in the IViewModel project/dll would mainly include properties that help the ViewModel know what is needed for binding. However, in such rare circumstances that it makes sense to communicate to the DataContext, the View can check if the DataContext implements an interfaces and calls a method the interface defines.

Creating an Interface for data binding in Views with WPF

Perhaps you have seen the same idea as me. A list of bound objects and an interface with a list of properties, have a lot in common. To start with, both are contracts. By adding Bindings in WPF, you are creating a contract that promises any code that uses the view that if such code has certain properties to bind to, the view will bind to them. Similarly an interface is a contract wherein an object that implements the interface is required to comply with the interface else a build error.

Look at the following UserControl view.

<UserControl x:Class="BindingsAsInterfaceExample.View.PeopleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="200"
             d:DesignWidth="300"
             >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <DataGrid ItemsSource="{Binding People}" Grid.Row="0" Grid.ColumnSpan="3" HeadersVisibility="Column" CanUserAddRows="False" />
        <Button Content="Add Person" Command="{Binding AddPersonCommand}" Grid.Row="1" Grid.Column="0" />
        <Button Content="Edit Person" Command="{Binding EditPersonCommand}" Grid.Row="1" Grid.Column="1" />
        <Button Content="Delete Person" Command="{Binding DeletePersonCommand}" Grid.Row="1" Grid.Column="2" />
    </Grid>
</UserControl>

There are four bindings in this view. It may be beneficial to make these bindings into a concrete contract using an interface.

public interface IPeopleViewBindings
{
    IList People { get; set; }
    ICommand AddPersonCommand { get; set; }
    ICommand EditPersonCommand { get; set; }
    ICommand DeletePersonCommand { get; set; }
}

Then when implementing the view model, have it implement the interface. Now if some binding value is missing, a compile time error occurs.

using System.Collections;
using System.Collections.Generic;
using System.Windows.Input;
using BindingsAsInterfaceExample.Interfaces;
using BindingsAsInterfaceExample.Model;
using MVVM;

namespace BindingsAsInterfaceExample.ViewModel
{
    class PeopleViewModel : ViewModelBase, IPeopleViewBindings
    {
        #region Properties
        public IList People
        {
            get { return _People ?? (_People = CreateSamplePeople()); }
            set { _People = value; }
        } private IList _People;

        public ICommand AddPersonCommand
        {
            get
            {
                return _AddPersonCommand ??
                    (_AddPersonCommand = new RelayCommand(f => AddPerson(), f => AddPersonCanExecute()));
            }
            set { _AddPersonCommand = value; }
        } private ICommand _AddPersonCommand;

        public ICommand EditPersonCommand
        {
            get
            {
                return _EditPersonCommand ??
                    (_EditPersonCommand = new RelayCommand(f => EditPerson(), f => EditPersonCanExecute()));
            }
            set { _EditPersonCommand = value; }
        } private ICommand _EditPersonCommand;

        public ICommand DeletePersonCommand
        {
            get
            {
                return _DeletePersonCommand ??
                    (_DeletePersonCommand = new RelayCommand(f => DeletePerson(), f => DeletePersonCanExecute()));
            }
            set { _DeletePersonCommand = value; }
        } private ICommand _DeletePersonCommand;
        #endregion

        #region Functions
        private IList CreateSamplePeople()
        {
            IList people = new List<Person>();

            people.Add(new Person() { FirstName = "John", MiddleName = "J.", LastName = "Johnson" });
            people.Add(new Person() { FirstName = "Mark", MiddleName = "M.", LastName = "Markson" });
            people.Add(new Person() { FirstName = "Thom", MiddleName = "T.", LastName = "Thompson" });

            return people;
        }

        private void AddPerson()
        {
            // ...
        }

        private bool AddPersonCanExecute()
        {
            return true;
        }

        private void EditPerson()
        {
            // ...
        }

        private bool EditPersonCanExecute()
        {
            return true;
        }

        private void DeletePerson()
        {
            // ...
        }

        private bool DeletePersonCanExecute()
        {
            return true;
        }
        #endregion
    }
}

This is solution is not without problems.

  1. Now when you add a binding to a view, you have to remember to add it to the interface as well, otherwise you are no better off.
  2. Interfaces don’t support private fields and a lot of the methods are private.

However, it is actually quite useful when creating an API that someone else is consuming. Users of the API documentation will be grateful for the interfaces.