Slippy
Slippy

Reputation: 185

WPF: How do I handle an event from a Model to dynamically update xaml in MVVM

I've hit a bit of a dead end in trying to figure this one out... Using the MVVM pattern in WPF, our C# Model fires an event to say something has happened. I want to be able handle that event in my ViewModel and then either kick of a storyboard or change the visibility of a hidden panel on the current Xaml Page. This has to be handled with no Code Behind.

I can sync for the event in my ViewModel, update a property to say what the name of that event is and fire a NotifyPropertyChanged even but how do I get that to either kick off a storyboard or map to a boolean true/false on the Visibility property of my Grid? The property I bind to hs to be the event name as different grids may be shown based on different events so I need a way of mapping this to a boolean. However the ideal solution would be to kick off a storyboard. I've looked at DataTriggers but they all seem to be linked to styles and not to actual pages.

Any ideas of how I can achieve this?

Thanks!

Upvotes: 2

Views: 954

Answers (3)

Robert Rossney
Robert Rossney

Reputation: 96702

From your comment, it seems to me like what you may want to do is expose an Event property of type object in your view model. When the view model receives an event, it sets Event to an object of a type appropriate for that event. In your XAML, you have this:

<ContentControl Content="{Binding Event}"/>

and in the resource dictionary define a DataTemplate for each specific type of event you want to display. If Event is null, nothing gets displayed. If Event contains an object that you've defined a DataTemplate for, it gets displayed using that template.

Yes, you'll need to create a class for each type of event (if you don't already have one).

Another way is to implement the poor man's template selector:

<TextBlock Text="This is displayed if Foo contains 'BAR'">
   <TextBlock.Style>
      <Style TargetType="TextBlock">
         <Setter Property="Visibility" Value="Collapsed"/>
         <Style.Triggers>
            <DataTrigger Property="Foo" Value="BAR">
               <Setter Property="Visibility" Value="Visible"/>
            </DataTrigger>
         </Style.Triggers>
      </Style>
   </TextBlock.Style>
</TextBlock>
<TextBlock Text="This is displayed if Foo contains 'BAZ'">
   <TextBlock.Style>
      <Style TargetType="TextBlock">
         <Setter Property="Visibility" Value="Collapsed"/>
         <Style.Triggers>
            <DataTrigger Property="Foo" Value="BAZ">
               <Setter Property="Visibility" Value="Visible"/>
            </DataTrigger>
         </Style.Triggers>
      </Style>
   </TextBlock.Style>
</TextBlock>

It's kind of stupidly verbose, but it's an easy way to handling a lot of mutually-exclusive display options.

Upvotes: 1

Rachel
Rachel

Reputation: 132548

I've used this in the past to kick off a storyboard in code-behind

Storyboard animation = (Storyboard)this.FindResource("ShowPanelStoryboard");
animation.Begin();

This code goes behind the View, not in the ViewModel. Personally, I don't mind some code behind my View providing it is only related the View. In the project I used this in, I added a listener to the VisibilityChanged event and when it got changed to Visible, I ran the storyboard.

As for showing your popup, there's a few ways. One of my favorites was just adding an IsPopupShown property to the ViewModel, binding my panel's visibility to it, and setting it to true anytime the popup should be shown. The ViewModel then handles the events that trigger the popup being shown or not.

An alternative as suggested by Dave White is to use a converter. If your value is not always true/false then you could create a converter that checks if a bound value is equal to the ConverterParameter, and return a Visibility value.

Upvotes: 1

Dave White
Dave White

Reputation: 3461

Bind the Visibility property on your grid, in Xaml, to the boolean property on your ViewModel.

<Grid Visibility="{Binding Path=VisiblePropertyOnViewModel}">

Now do whatever you need in your ViewModel and set the property. As long as it does INotifyPropertyChanged or is a DependencyProperty, it will work.

I'd have to do more digging to figure out how to kick off a Storyboard, but I have no doubt it would be almost as easy. Storyboards can be kicked off by PropertyTriggers as well I believe. I'll leave this to get you started.

Upvotes: 0

Related Questions