in

Utah .NET User Group

Home of Utah's professional .NET developers.

Joe's Blog

November 2008 - Posts

  • Building a Databound WPF Menu Using a HierarchicalDataTemplate

    I had a colleague ask me how he could solve a databinding problem while building a WPF Menu.  The immediate answer wasn’t apparent to me, though it’s actually quite simple.  A while back Karl Shifflett wrote up an excellent example of doing something similar.  I take his example one step further by showing how you can easily bind  properties to the MenuItem instead of assigning one-time values.

    Download Source:  WPFDataBoundMenu.zip

    We’re going to use a simple Business Object which represents our MenuItem.  It has four properties: MenuText, IsEnabled, Command, and Children.

    public class MyBusinessObject : INotifyPropertyChanged
    {
        private bool _isEnabled;
        private string _menuText;
        private ICommand _command;
        private ObservableCollection<MyBusinessObject> _children;
     
        public event PropertyChangedEventHandler PropertyChanged;
     
        public MyBusinessObject()
        {
            Children = new ObservableCollection<MyBusinessObject>();
        }
     
        public string MenuText
        {
            get { return _menuText; }
            set
            {
                _menuText = value;
                RaisePropertyChanged("MenuText");
            }
        }
     
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                RaisePropertyChanged("IsEnabled");
            }
        }
     
        public ICommand Command
        {
            get { return _command; }
            set
            {
                _command = value;
                RaisePropertyChanged("Command");
            }
        }
     
        public ObservableCollection<MyBusinessObject> Children
        {
            get { return _children; }
            set
            {
                _children = value;
            }
        }
     
        private void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
     
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    We’ll build our window to include a Menu and  a Button.  When we click the button we want to toggle the IsEnabled property of one of our Business Objects.

    image 

    <Window
        x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="Window1"
        Height="400"
        Width="700">
     
        <Window.Resources>
     
            <HierarchicalDataTemplate
                DataType="{x:Type local:MyBusinessObject}"
                ItemsSource="{Binding Path=Children}">
     
                <ContentPresenter
                    Content="{Binding MenuText}"
                    Loaded="ContentPresenter_Loaded"
                    RecognizesAccessKey="True" />
     
            </HierarchicalDataTemplate>
     
        </Window.Resources>
     
        <Grid
            Margin="10">
     
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
     
            <Menu
                ItemsSource="{Binding}"/>
     
            <StackPanel
                Grid.Row="1">
                <Button
                    Content="Toggle Enable"
                    Click="Enable_Click"/>
            </StackPanel>
     
        </Grid>
    </Window>

    In our code-behind for the window we build a collection of MyBusinessObject’s.  We then assign that collection to the DataContext of our Window.  This allows the Menu control to bind its ItemsSource to the current value of the DataContext (ItemsSource="{Binding}").  Where we do the magic is in the ContenPresenter_Loaded event handler.  This is fired when the MenuItems are being built.  Inside the handler we get a reference to the ContenPresenter then walk up the tree to it’s Parent MenuItem.  UtilityMethods.FindParent accomplishes this task by using the VisualTreeHelper and recursively walking the tree.  We then can get a reference to our MyBusinessObject through the DataContext of the MenuItem.  This allows us to build bindings, in code, to bind to various properties.  It’s important to remember that we can do lots of the same things in code in which we can do in XAML.  XAML is just usually funner.  =]

    public partial class Window1 : Window
    {
        private ObservableCollection<MyBusinessObject> _options;
     
        public Window1()
        {
            InitializeComponent();
     
            _options = new ObservableCollection<MyBusinessObject>();
     
            // build simple menu structure
            MyBusinessObject menuTwo = new MyBusinessObject
            {
                MenuText = "Two",
            };
     
            menuTwo.Children.Add(
                new MyBusinessObject
                {
                    MenuText = "Child 1"
                }
            );
            menuTwo.Children.Add(
                new MyBusinessObject
                {
                    MenuText = "Child 2",
                    IsEnabled = false
                }
            );
     
            _options.Add(
                new MyBusinessObject
                {
                    MenuText = "One"
                }
            );
            _options.Add(menuTwo);
     
            DataContext = _options;
        }
     
        private void ContentPresenter_Loaded(object sender, RoutedEventArgs e)
        {
            // get the content presenter
            ContentPresenter contentPresenter =
                sender as ContentPresenter;
     
            // get reference to menu item
            MenuItem menuItem =
                UtilityMethods.FindParent<MenuItem>(contentPresenter);
     
            // get reference to business object
            MyBusinessObject myBusinessObject =
                menuItem.DataContext as MyBusinessObject;
     
            // create bindings
            Binding isEnabledBinding = new Binding("IsEnabled");
            isEnabledBinding.Mode = BindingMode.TwoWay;
            isEnabledBinding.Source = myBusinessObject;
            menuItem.SetBinding(MenuItem.IsEnabledProperty, isEnabledBinding);
     
            Binding commandBinding = new Binding("Command");
            commandBinding.Mode = BindingMode.TwoWay;
            commandBinding.Source = myBusinessObject;
            menuItem.SetBinding(MenuItem.CommandProperty, commandBinding);
        }
     
        private void Enable_Click(object sender, RoutedEventArgs e)
        {
            // toggle IsEnabled
            _options[1].Children[1].IsEnabled =
                !_options[1].Children[1].IsEnabled;
        }
    }

    And that’s it!  I hope that helps!

    Download Source:  WPFDataBoundMenu.zip

    Joe

    Posted Nov 25 2008, 06:49 PM by Joe's Blog
    Filed under: ,
  • UI Design Patterns Presentation Code + Slide Deck

    Thank you to everyone who came to my presentation on UI Design patterns!  It was great to see so many people interested in patterns for building user interfaces.

    One user group member recorded the presentation on his laptop's webcam; I should have that available for download this weekend.  The video is so-so, but the audio isn't too bad.  Thanks Walt!

    Links

    Download Code & Slides - http://xamlcoder.com/joe/downloads/UIDesignPatterns2008.zip

    Martin Fowler MVC
    Martin Fowler MVP
    ASP.NET MVP & Other Patterns
    Karl Shifflett MVVM

    Requirements

    • Visual Studio 2008 SP1
    • Silverlight Tools for Visual Studio
    • NUnit (included with code)
    • Rhino Mocks (included with code

    There's a small "gotcha" with the Silverlight sample.  The implemenation is slightly different than that of it's WPF counterpart.  Silverlight Dependency properties do not automatically fire change notifications when their values have changed.  Therefore if you want property change notifications your control (read DependencyObject which the Dependency Property is a member of) itself has to implement the INotifyPropertyChanged interface, or you can do what I've done here and set the DataContext of a container control.

  • Utah .NET User Group Presentation - UI Design Patterns

    Join me this week at the Utah .NET User Group where I’ll be giving a presentation on UI Design Patterns.

    UI Design Patterns

    In this session we’ll explore three UI design patterns: Model View Controller (MVC), Model View Presenter (MVP), and Model View ViewModel (MVVM).  We’ll prove that you can reuse the same logic to drive a WinForms, ASP.NET, WPF, or Silverlight "View".  We’ll also see how using these patterns allow the bulk of your UI to be testable using testing frameworks such as NUnit and Rhino Mocks.

    Date: Thursday, November 13th, 2008

    Time: 6:00 PM

    Place: Neumont University 3rd Floor (10701 South River Front Parkway, South Jordan)

    See you there!

  • Building composite Applications Using PRISM Presentation

    Thank you to everyone who attended my presentation on PRISM at the Utah Code Camp this past weekend.  Here’s a link to my sample code and slide deck.

    http://xamlcoder.com/joe/downloads/PRISM-UTCodeCamp2008.zip

    Note that you’ll need VS2008 SP1 with the Silverlight Tools for Visual Studio 2008 SP1 installed to run the Silverlight demo.

Copyright © 2000-2007, Utah .NET User Group
Powered by Community Server (Commercial Edition), by Telligent Systems