在尝试绑定MenuItem的IsChecked属性时感到困惑

时间:2015-04-02 15:13:24

标签: c# wpf xaml data-binding menuitem

在浏览StackOverflow和其他网站后,我发现人们对MenuItemsContextMenus的绑定属性和命令存在很多问题,因为ContextMenu不属于WPF视觉树。无论如何,我尝试了一些不同的解决方案,但没有运气。

我有MenuItem,是ContextMenu的一部分。 ContextMenu是窗口的一部分,该窗口在其代码后面绑定到ViewModel,如下所示:

public partial class Window1 : Window
{
    public MainWindowViewModel ViewModel { get { return DataContext as MainWindowViewModel; } } 

    public Window1()
    {
        InitializeComponent();

        //There is a property in the App.xaml.cs file that refers to MainWindowViewModel
        DataContext = App.MainWindowViewModel = new MainWindowViewModel();
    }
}

我尝试在MainWindowViewModel中绑定的属性:

private bool _askBeforeDownloading_Checked = true;

public bool AskBeforeDownloading_Checked
{
    get { return _askBeforeDownloading_Checked; }
    set
    {
        _askBeforeDownloading_Checked = value;
        NotifyPropertyChange(() => AskBeforeDownloading_Checked);
    }
}

我目前在XAML中的尝试:

<Button Name="Button_1" >
    <Button.ContextMenu>
        <ContextMenu x:Name="MainContextMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" >
            <MenuItem >
                <MenuItem IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}, Path=PlacementTarget.AskBeforeDownloading_Checked}" />
            </MenuItem>
        </ContextMenu>
    </Button.ContextMenu>
</Button>

我根据this question上接受的答案以及this guide提出了我当前的XAML。我错过了什么?我没有收到任何输出错误,但未检查MenuItem。我有没有用PlacementTarget做什么?

更新:我认为重要的是要注意我的ContextMenuButton的子控件。我已将它添加到我的XAML中。

更新2 :在我的应用程序上使用Snoop后,我发现我的Button会自动从MainWindowViewModel继承。但是,我忽略了可能会影响我的代码的父MenuItem。我已经更新了我的XAML并为第一次错过而道歉。

2 个答案:

答案 0 :(得分:2)

DataContext继承自<ContextMenu>,因此您无需在绑定中编写任何特殊内容。

<Button Name="Button_1" >
    <Button.ContextMenu>
        <ContextMenu x:Name="MainContextMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" >
            <MenuItem IsCheckable="True" IsChecked="{Binding AskBeforeDownloading_Checked}" />
        </ContextMenu>
    </Button.ContextMenu>
</Button>

为了更详细地解释,DataContext中的<ContextMenu>绑定说:

  • “RelativeSource Self”表示“此项目”,即<ContextMenu>
  • “PlacementTarget”表示“此项目所在的项目”,在本例中为<Button>对象

所以你说要将ContextMenu.DataContext属性绑定到Button.DataContext属性。

该属性应该是您的MainWindowViewModel,因此您可以使用普通绑定绑定到DataContext上的.AskBeforeDownloading_Checked属性。

或者,您可以从.DataContext删除<ContextMenu>绑定,并保持<MenuItem>绑定与您拥有的绑定类似,但您需要引用Button.DataContext.AskBeforeDownloading_Checked },而不是你现在拥有的Button.AskBeforeDownloading_Checked

<Button Name="Button_1" >
    <Button.ContextMenu>
        <ContextMenu x:Name="MainContextMenu>
            <MenuItem IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AskBeforeDownloading_Checked}" />
        </ContextMenu>
    </Button.ContextMenu>
</Button>

在这两种方法中,我更喜欢第一种方法,因为如果你将更多的项目/属性绑定到Button.DataContext属性,它允许更少的代码。

答案 1 :(得分:1)

您需要添加PlacementTarget.DataContext。请参阅下面的代码。

<Button Name="Button_1" >
        <Button.ContextMenu>
            <ContextMenu x:Name="MainContextMenu">
                <MenuItem IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AskBeforeDownloading_Checked}" />
            </ContextMenu>
        </Button.ContextMenu>
    </Button>