# Friday, December 05, 2008

This post presents a problem that has been approached by others before, but I thought I’d offer yet another possible solution. But first, let’s introduce the problem!

In my experience, real world applications (aka NOT demos) don’t display data that was hard-coded in an application. For my part, the data is usually coming from some remote service or endpoint, so I’m either working with some proxy to a WCF, ASMX, or remoting endpoint. It seems that most WPF demos that showcase data-binding imagine a scenario where the data is readily available to the designer which allows them, at design-time, to see what the application might look like with real data loaded.

Check out the below screenshot of an amazing application that I created this morning.

image

As you can tell, I’m displaying a list of accounts by name and balance. The UI on this thing is unbelievable, too, because it also makes the balance red when their balance is below zero. Go WPF!

Seriously, though, I’ve tried to structure this like I might a real application. I’m a huge fan of the CompositeWPF library (*cough* Prism *cough*), so I’m using a Model-View-Presenter approach here, where the View is binding to a PresentationModel. You can see some examples of this in the StockTrader reference application that ships with CompositeWPF. The presenter’s only job is to hook up the data binding to the view and then load the PresentationModel up with data from the service. (Note that it would be very easy to add threading support here so that, while pulling data from IService, we don’t lock up the UI)

public class Presenter  
{  
    private readonly IView _view;  
    private readonly IService _service;  
    private readonly PresentationModel _presentationModel;  
  
    public Presenter(IView view, IService service, PresentationModel presentationModel)  
    {  
        _view = view;  
        _service = service;  
        _presentationModel = presentationModel;  
    }  
  
    public void Run()  
    {  
        _view.Model = _presentationModel;  
        LoadAccounts();  
    }  
  
    private void LoadAccounts()  
    {  
        foreach (var acct in _service.GetAccounts())  
            _presentationModel.Accounts.Add(acct);  
    }  
}

The PresentationModel only exposes an ObservableCollection of Accounts.

public class PresentationModel  
{  
    private readonly ObservableCollection<Account> _accounts = new ObservableCollection<Account>();  
    public ObservableCollection<Account> Accounts  
    {  
        get  
        {  
            return _accounts;  
        }  
    }  
}

The code for Window1.xaml is below.

<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="300"  
  Width="300">  
    
  <local:AccountDisplay  
    DataContext="{Binding}" />  
</Window>

I’m just tying the DataContext for my AccountDisplay UserControl to whatever Binding is set to the Window. This allows the data binding to just flow through the rest of the application. This is very flexible. But what about the code behind? It is pretty basic, too.

public partial class Window1 : Window, IView  
{  
    public Window1()  
    {  
        InitializeComponent();  
  
        var presenter = new Presenter(this, new RealService(), new PresentationModel());  
        presenter.Run();  
    }  
 
    #region IView Members  
  
    public object Model  
    {  
        get { return DataContext; }  
        set { DataContext = value; }  
    }  
 
    #endregion  
}

The sample isn’t using CompositeWPF, but if you’re familiar with it, you should realize that it would be very easy to plug it in. In fact, my example is screaming Inversion of Control because of the Dependency Injection that I’m already using with the Presenter. A conversion to using the CompositeWPF would start with replacing the local declaration of the AccountDisplay user control with a region and associated module and you’ll be well on your way.

The real display is in AccountDisplay. Here is its source:

<UserControl  
  x:Class="WpfApplication1.AccountDisplay"  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  xmlns:local="clr-namespace:WpfApplication1"  
  Height="300"  
  Width="300">  
    
  <UserControl.Resources>  
    <local:BalanceToBrushConverter  
      x:Key="BalanceToBrushConverter" />  
  </UserControl.Resources>  
  
  <ItemsControl  
    ItemsSource="{Binding Path=Accounts}">  
  
    <ItemsControl.ItemTemplate>  
      <DataTemplate>  
  
        <StackPanel  
          Orientation="Horizontal">  
          <Border  
            CornerRadius="5"  
            Padding="5"  
            BorderBrush="Black"  
            BorderThickness="2">  
            <TextBlock  
              Text="{Binding Path=Name}" />  
          </Border>  
          <Border  
            CornerRadius="5"  
            Padding="5"  
            BorderBrush="Black"  
            BorderThickness="2">  
            <TextBlock  
              Foreground="{Binding Path=Balance, Converter={StaticResource BalanceToBrushConverter}}"  
              Text="{Binding Path=Balance}" />  
          </Border>  
        </StackPanel>  
      </DataTemplate>  
    </ItemsControl.ItemTemplate>  
  
  </ItemsControl>  
</UserControl>

Here, I’m just using relative binding (Binding Path=Property) here. This means I’ll pick up data binding from the DataContext, which was set back in Window1.xaml (once again, a result of that flowing data binding).

So, where’s the problem? Let’s look at this from the designer perspective by opening AccountDisplay.xaml in Blend.

image

It… it looks really great. So… white and everything. Anyone know what the problem is? My Presenter is the guy who does the work to return accounts to bind to, but Blend is just showing us the XAML. This is good – we don’t want the fact that we’re designing this to actually run our code and hit our services. But… we still want some test data to design with, right? We could add some data to our XAML file… but then that affects us when we actually run the application. Besides, I personally want test data to match the structure of the model I’m binding to.

Here’s what I’m doing to fix this right now. I added the following 3 lines of code to AccountDisplay.xaml.

<local:Designer.DataContext>  
  <local:BlendPresentationModel />  
</local:Designer.DataContext>

That doesn’t tell you much, so I’ll show you the Designer class that is being referenced now.

/// <summary>  
/// Allows the use of design-time only data binding... seems to only work  
/// in Blend and not the VS designer...  
/// </summary>  
public static class Designer  
{  
    public static readonly DependencyProperty DataContextProperty =  
        DependencyProperty.RegisterAttached("DataContext", typeof (object), typeof (Designer),  
                                            new PropertyMetadata(OnDataContextChanged));  
  
    private static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  
    {  
        SetDataContext(d, e.NewValue);  
    }  
  
    public static void SetDataContext(DependencyObject d, object value)  
    {  
        var element = d as FrameworkElement;  
        if (element == null) return;  
  
        if (DesignerProperties.GetIsInDesignMode(element))  
            element.DataContext = value;  
    }

    public static object GetDataContext(DependencyObject d)
    {
        var element = d as FrameworkElement;
        if (element == null) return null;

        if (!DesignerProperties.GetIsInDesignMode(element))
            return null;

        return element.DataContext;
    }  
}

A few of things to note. I have a Dependency Property called DataContext first. I’m using a Dependency Property so that WPF data binding works. It can take any object (hence the typeof(object) parameter. When it changes, I call off to SetDataContext with the new value. Next important thing to note – DesignerProperties.GetIsInDesignMode. I try to cast the owner of my Designer instance (which is typically going to be a UserControl or Window or other UI element) to a FrameworkElement. I’m using FrameworkElement because it is the highest object in the hierarchy that provides the DataContext property. Then, if we’re in Design mode, I override the DataContext with my Designer DataContext.

In the XAML, what ends up getting set is a BlendPresentationModel, which looks like this:

public class BlendPresentationModel : PresentationModel  
{  
    public BlendPresentationModel()  
    {  
        var accounts = new List<Account>  
                           {  
                               new Account  
                                   {  
                                       Name = "Bob's Stuff",  
                                       Balance = 1000000  
                                   },  
                               new Account  
                                   {  
                                       Name = "Cheap Skate",  
                                       Balance = -100  
                                   }  
                           };  
        foreach (var acct in accounts)  
            Accounts.Add(acct);  
    }  
}

With my approach, I’ve created an object that inherits from my PresentationModel, so the object I’m binding my UI to is the same type that I’m using when running, but I’m providing test data instead. This is what it looks like in Blend now:

image

In one of my projects, I’ve been dropping these guys around in various UserControls and even one at the top level Window so that I can see what it all looks like together. So far, it is working well.

The biggest problem I’ve got with this solution so far is that the Visual Studio designer doesn’t render the test data. I would guess that this would be fixed at some point – honestly, the rendering of XAML should be the same between Blend and Visual Studio and, if it isn’t, it should be fixed.

Karl Shifflett posts a solution to this as well – my solution is basically just my own take on what he’s already done, so thanks to him for the initial idea. I wasn’t using Resources for binding, which is the primary reason I started with my own solution.

Also, Laurent Bugnion has a great article on various methods to accomplish this as well. I particularly like the feature he shares where Blend can create sample data. I’m very hopeful that this functionality is improved and expanded in future versions of Blend.

I hope this post helps out! Also, if I’m doing something that doesn’t make sense or if there is a better way to do something, please let me know.

UPDATE:
Thanks to Brian Genisio for the suggestion to add the GetDataContext method to my Designer class.

posted on Friday, December 05, 2008 1:13:38 PM (Central Standard Time, UTC-06:00)  #    Comments [4]
# Wednesday, November 19, 2008

I’ve been doing some WPF work lately. WPF is ridiculously powerful and provides a lot more than WinForms. On the other hand – wow, the learning curve is quite steep. I think I’m improving, though.

So, the scenario. I wanted to be able to let a user click on an item in a ListBox and drag across, selecting multiple items in the process. Basically, I want to emulate the behavior that the Outlook calendar provides.

I ended up coding up the following XAML to get the behavior:

<ListBox
  x:Name="myListBox"
  SelectionMode="Multiple"
  ItemsSource="{Binding Path=SomeIEnumerableOnMyDataContext}"
  >
  <ListBox.Resources>
    <Style
      TargetType="{x:Type ListBoxItem}"
      >
      <EventSetter
        Event="PreviewMouseLeftButtonDown"
        Handler="ListBoxItem_PreviewMouseLeftButtonDown" />
      <EventSetter
        Event="PreviewMouseUp"
        Handler="ListBoxItem_PreviewMouseUp" />
      <EventSetter
        Event="PreviewMouseMove"
        Handler="ListBoxItem_PreviewMouseMove" />
      <EventSetter
        Event="PreviewMouseRightButtonDown"
        Handler="ListBoxItem_PreviewMouseRightButtonDown" /> 
    </Style>
</ListBox>

The problem with this code is that Blend (currently v2 SP1) doesn’t like EventSetters.

image

I wanted to keep the events hooked up so that, while testing, I could keep the behavior but, at the same time, I want to be able to at least try to design in blend. So I took to implementing the above XAML in code.

Sacha Barber has a good article on converting from XAML to code and back that helped a lot but it didn’t get me quite there.

Here is how to programmatically create one of the EventSetters in code:

var style = new Style(typeof (ListBoxItem)); 
 
style.Setters.Add(
    new EventSetter(PreviewMouseLeftButtonDownEvent,
                    new MouseButtonEventHandler(OnPreviewMouseLeftButtonDown)));

It’s pretty straightforward, but actually hooking this style into my ListBox was what got me confused next.

Setting the ListBox’s style to my style instance didn’t work and then I got stuck on how to plug my style into the ListBox’s ResourceDictionary (via the Resources property). The XAML doesn’t specify a Key anywhere, but the Resources’s Add method requires a key. I tried creating my own key and also specifying a null key, but I still didn’t get the behavior I wanted.

StackOverflow’s goal of being the place for one-off questions like this is starting to work because I stumbled across my answer via Google. I didn’t realize that, in the above XAML, when the Style specifies its TargetType, the type is implicitly the Key in the ResourceDictionary.

So the solution is this:

Resources.Add(typeof (ListBoxItem), style);

Easy enough.

posted on Wednesday, November 19, 2008 12:01:01 PM (Central Standard Time, UTC-06:00)  #    Comments [2]