【问题标题】:Binding checked menu items to ViewModel commands将选中的菜单项绑定到 ViewModel 命令
【发布时间】:2012-02-18 00:40:56
【问题描述】:

我在 XAML 中定义了 3 个菜单项(使用 WPF-MDI):

<MenuItem Header="_Generic" Name="Generic" ToolTip="Generic Visual Studio designer theme" 
          Command="{Binding Path=SelectGenericTheme}"/>
<MenuItem Header="_Luna" Name="Luna" ToolTip="Blue Windows XP theme"
          Command="{Binding Path=SelectLunaTheme}"/>
<MenuItem Header="_Aero" Name="Aero" ToolTip="Windows Vista/7 theme" 
          Command="{Binding Path=SelectAeroTheme}"/>

以及 ViewModel 中命令和当前选择的定义:

    public enum ESelectedTheme
    {
        Generic,
        Luna,
        Aero
    }

    ESelectedTheme _selectedTheme;

    ICommand _selectGenericThemeCommand;
    public ICommand SelectGenericThemeCommand
    {
        get { return _selectGenericThemeCommand ?? (_selectGenericThemeCommand = new RelayCommand(param => SelectGenericTheme(), 
            param => true)); }
    }

    void SelectGenericTheme()
    {
        _selectedTheme = ESelectedTheme.Generic;
    }


    ICommand _selectLunaThemeCommand;
    public ICommand SelectLunaThemeCommand
    {
        get
        {
            return _selectLunaThemeCommand ?? (_selectLunaThemeCommand = new RelayCommand(param => SelectLunaTheme(),
                param => true));
        }
    }

    void SelectLunaTheme()
    {
        _selectedTheme = ESelectedTheme.Luna;
    }


    ICommand _selectAeroThemeCommand;
    public ICommand SelectAeroThemeCommand
    {
        get
        {
            return _selectAeroThemeCommand ?? (_selectAeroThemeCommand = new RelayCommand(param => SelectAeroTheme(),
                param => true));
        }
    }

    void SelectAeroTheme()
    {
        _selectedTheme = ESelectedTheme.Aero;
    }

我有 2 个问题(希望在一篇帖子中允许):

  1. 我想将 XAML 中的 IsChecked 属性绑定到选定的值 (_selectedTheme)。我想我需要写一个转换器,但我不知道怎么做。
  2. 我制作了 3 个 ICommand 副本(每个主题一个)...如果我有 20 个主题会怎样...有没有办法让这段代码参数化?

提前致谢。

【问题讨论】:

  • 你可以指定一个CommandParameter,你问如何参数化一个命令?您是否一直忽略param =&gt; ... 却不知道如何使用它?
  • 使用参数化我的意思是只使用 1 个命令而不是 3 个命令(但我会检查 CommandParameter 的工作原理,也许这会有所帮助)。感谢您的评论。
  • 对于RelayCommand(T),将“true”作为谓词传递是没有意义的,因为它一开始就是默认的。
  • @m-y: 取决于实现...
  • @H.B.我想可能有一个博客发布了RelayCommand(T) 的一个版本,其中只有一个构造函数接受两个参数,但谷歌搜索结果都只允许传入Action(T)

标签: wpf xaml command menuitem ischecked


【解决方案1】:

没有必要对命令进行参数化,因为绑定将完成所有操作,但如前所述,可以使用CommandParameter。此处转换器将获取枚举参数。

一个例子:

<MenuItem Header="_Description" IsCheckable="True"
        IsChecked="{Binding Path=DisplayMode_Current,
                            Converter={StaticResource EnumToBooleanConv},
                            ConverterParameter=Description}" />
<MenuItem Header="_Web-Page" IsCheckable="True"
        IsChecked="{Binding Path=DisplayMode_Current,
                            Converter={StaticResource EnumToBooleanConv},
                            ConverterParameter=WebPage}" />

转换器可能如下所示:

public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // You could also directly pass an enum value using {x:Static},
        // then there is no need to parse
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        if (Enum.IsDefined(value.GetType(), value) == false)
            return DependencyProperty.UnsetValue;

        object parameterValue = Enum.Parse(value.GetType(), parameterString);

        return parameterValue.Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        return Enum.Parse(targetType, parameterString);
    }
}

由于 XAML 仍然很冗长(而且是多余的!),您可以通过将父级 MenuItemItemsSource 绑定到枚举值来进一步处理它,然后使用 ItemTemplateItemContainerStyle

【讨论】:

  • 我猜 SelectedTheme(ViewModel 中的属性)应该是一个依赖属性?如果是这样......我仍然需要学习很多关于 WPF 的知识。
  • @MichelKeijzers:不,永远不要在虚拟机中使用依赖属性,你知道INPChow to implement it,对吧?它应该只是实现该接口以绑定通知的普通属性。
  • 是的,我正在使用它...而不是我必须再次检查我的代码,因为在更改菜单项后我没有看到枚举值被更改...可能是我的错...调试 XAML 代码非常困难。
  • @MichelKeijzers:您绑定的属性将被更改,所有 MenuItems - 因为它们都绑定到它 - 然后将更新并因此被取消选中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-11
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 2016-06-04
相关资源
最近更新 更多