Search code examples
mvvmbindingtriggersmenuitemdatatrigger

Trigger when view model property equals menu item's header


I have a property "Mode" on my view model. Whenever this property changes, I want to see if it is equal to any menu item header in my context menu. If it is equal, I want the IsChecked property of that menu item to be set to true. How can this be accomplished?

I tried to set the value with the following line:

({Binding RelativeSource={RelativeSource Self}, Path=Header})

but you cannot use binding for the value. Here is the rest of my attempt with the value left blank currently:

<ContextMenu>
    <ContextMenu.ItemContainerStyle>
       <Style TargetType="{x:Type MenuItem}">
           <Setter Property="IsChecked" Value="False" />
           <Style.Triggers>
                <DataTrigger Binding="{Binding Mode}" Value="???">
                     <Setter Property="IsChecked" Value="True"></Setter>
                </DataTrigger>
            </Style.Triggers>
       </Style>
    </ContextMenu.ItemContainerStyle>
    <MenuItem Header="{x:Static Name:ContextMenuStartNames.1}"/>
    <MenuItem Header="{x:Static Name:ContextMenuStartNames.1}"/>
    <MenuItem Header="{x:Static Name:ContextMenuStartNames.3}"/>
</ContextMenu>

Solution

  • You can use a MultiValueConverter.

    public class ModeMultiConverter:IMultiValueConverter 
    {
        #region Implementation of IMultiValueConverter
    
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values.Length != 2 || values[0] == null || values[1] == null)
                return Binding.DoNothing;
    
            var mode = values[0].ToString();
            var header = values[1].ToString();
            return mode == header;
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    
        #endregion
    }
    

    And in Xaml:

    <MenuItem.IsChecked>
        <MultiBinding Converter="{StaticResource ModeMultiConverter}" Mode="OneWay">
            <Binding Path="PlacementTarget.DataContext.Mode" RelativeSource="{RelativeSource AncestorType=ContextMenu}"/>
            <Binding Path="Header" RelativeSource="{RelativeSource Self}"/>
        </MultiBinding>
    </MenuItem.IsChecked>
    

    You can remove the code in ItemContainerStyle.