"Mo"
Published on

Programmatically adding EventSetters in WPF

Authors

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.

Expression Blend Error

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.