Louis Rhys
Louis Rhys

Reputation: 35637

How to make a WPF content conditional on some bound data?

I want to create a menu item but the displayed text depends on a property of the view model. If the property IsPlaying is true, the MenuItem text should be "Pause", else it should be "Play".

Without this condition, the MenuItem should be something like:

<MenuItem Header="_Play" Command="{Binding Path=PlayCommand}" />

But, "Play" and "Pause" should interchange (and if possible PlayCommand should interchange with PauseCommand too, but this can be worked by having both the logic of PlayCommand and PauseCommand in PlayCommand)

Upvotes: 3

Views: 2887

Answers (4)

Michael Brown
Michael Brown

Reputation: 9153

In WPF you can use a DataTrigger to change the content based on state in your viewmodel (you could even use this technique to swap out the template). Another alternative is to use the VisualStateManager (the distant cousin of datatriggers created for Silverlight's absence thereof that was then backported to WPF as well) to do a similar change from one state (IsPlaying) to the next (!IsPlaying).

I would love to give a more detailed example but it's past my bedtime. Maybe later today.

Upvotes: 1

slugster
slugster

Reputation: 49965

The best thing for this is a converter. Your code will look something like this:

<UserControl xmlns:myConverters="MyRandomNamespace">
    <UserControl.Resources>
        <myConverters:MyMenuTextConverter x:Key="MyMenuTextConverter" />
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">
        <TextBlock Text="{Binding IsPlaying, Converter={StaticResource MyMenuTextConverter }}" />
    </Grid>

</UserControl>

and in the converter:

namespace MyRandomNamespace 
{
    public class MyMenuTextConverter : IValueConverter 
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
        {
            if ((bool) value == true)
               return "Pause";

            return "Play";
        }
    }
}

I've used a TextBlock to display the concept behind the binding, all you have to do is use the same binding syntax on the appropriate property of the MenuItem. I'm also returning literal text from the converter which is not optimal (personally i like my text converters to retrieve their values from a string resource file so that my app is culture aware), but you get the idea.

Upvotes: 1

itowlson
itowlson

Reputation: 74842

A couple of ways to do this:

  1. Use a Trigger. Set a Trigger on IsPlaying = True, and set the Header and Command to Pause and PauseCommand respectively.
  2. Have two menu items, Play and Pause, and use a pair of triggers to set their Visibility according to IsPlaying. (You could also data-bind Visibility, but using triggers avoids the need to define a BooleanToInvisibilityConverter.)

Upvotes: 1

Yogesh
Yogesh

Reputation: 14608

The simplest way to do this is first you should bind the Header to a string Caption property in your viewmodel which returns Play or Pause based on the value of IsPlaying and implement INotifyPropertyChanged. After this, just throw change notification for Caption also when IsPlaying is changed.

Although you can use a converter, but in this case it will be an overkill.

Upvotes: 3

Related Questions