如何将MenuItem作为其子控件的命令参数传递

时间:2014-03-09 17:58:00

标签: c# wpf xaml

我有类似下面的内容。对于MenuItem,我在这里将MenuItem的对象作为CommandParameter传递。这对我来说很好。我的MenuItem拥有RadioButton,我想对此CommandParameter使用MenuItem RadioButton值。谁能帮助我如何做到这一点。在此先感谢。

<MenuItem Header="Name"
          VerticalAlignment="Center"
          VerticalContentAlignment="Center"
          Command="{Binding SortCommand}"
          CommandParameter="{Binding RelativeSource={RelativeSource Self}}">
      <MenuItem.Icon>
           <RadioButton VerticalAlignment="Center"
                        Margin="3"
                        IsChecked="True"
                        GroupName="sort"
                        Command="{Binding SortCommand}"
                        CommandParameter="..." />
      </MenuItem.Icon>
</MenuItem>

现在Command仅在我选择MenuItem时才会执行。我想在用户同时选择RadioButton时也这样做。以下是我正在使用的代码。

public void OnSortCommandExecuted(object menuItem)
{
   MenuItem menu = menuItem as MenuItem;
   if (menu != null)
   {
      ((RadioButton)menu.Icon).IsChecked = !((RadioButton)menu.Icon).IsChecked;
      this.eAggregator.GetEvent<ImagesSortedEvent>().Publish(menu.Header.ToString());    
   }
}

1 个答案:

答案 0 :(得分:1)

就像我在评论中所说的那样,将UI组件作为CommandParameter传递给ViewModel并不是一个好习惯,因为ViewModel不应该知道View。

我建议你在ViewModel中使用正确的绑定。 在ViewModel中创建一个bool属性,并与radioButton的IsChecked DP绑定。这样您就不必从View中传递任何CommandParameter,只需从命令执行方法中检查bool属性的状态。


  

现在,为什么无法从RadioButton访问MenuItem

RadioButton 与MenuItem不在同一个Visual树中。

因此,您无法使用RelativeSource前往MenuItem。另外ElementName绑定在这里不起作用,因为这两个元素应该位于同一个Visual Tree中。

在这种情况下,你可能会发现over net使用x:Reference,其中两个元素不在同一个Visual树中但在这里不起作用,因为它会产生循环依赖。

最后,您必须使用它来使用Freezable类对象来保存MenuItem的实例并在绑定中使用该资源。

首先您需要定义派生自Freezable的类:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object),
                                     typeof(BindingProxy));
}

你可以在XAML中使用它来传递MenuItem:

    <MenuItem Header="Name"
              x:Name="menuItem"
              VerticalAlignment="Center"
              VerticalContentAlignment="Center"
              Command="{Binding SortCommand}"
              CommandParameter="{Binding RelativeSource={RelativeSource Self}}">
        <MenuItem.Resources>
            <local:BindingProxy x:Key="proxy"
                                Data="{Binding Source={x:Reference menuItem}}"/>
        </MenuItem.Resources>
        <MenuItem.Icon>
            <RadioButton VerticalAlignment="Center"
                         Margin="3"
                         IsChecked="True"
                         GroupName="sort"
                         Command="{Binding SortCommand}"
                         CommandParameter="{Binding Data.CommandParameter,
                                              Source={StaticResource proxy}}"/>
        </MenuItem.Icon>
    </MenuItem>

当然,您需要在XAML中声明local命名空间。

PS - 我仍然坚持使用第一种方法在ViewModel中定义正确的绑定。


<强>更新

如果MenuItem位于ContextMenu下,则无法RelativeSource绑定。上述方法适用于该情况。

但是如果您将MenuItem直接作为某个控件(如Menu)的子项放置,RelativeSource绑定将起作用:

CommandParameter="{Binding CommandParameter,
       RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=MenuItem}}"