WPF MVVM ContextMenu 绑定 IsOpen 到模型 [英] WPF MVVM ContextMenu binding IsOpen to Model

查看:57
本文介绍了WPF MVVM ContextMenu 绑定 IsOpen 到模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有关联菜单的按钮.我可以右键单击按钮并按预期显示上下文菜单,但是我希望能够在另一个事件(例如左键单击或拖放样式事件)之后显示上下文菜单.

I have a button with a context menu associated to it. I can right click on the button and show the context menu as you would expect, however I want to be able to show the context menu after another event, such as a left click, or a drag and drop style event.

我试图通过将上下文菜单的 IsOpen 属性绑定到视图模型来执行此操作,但这并没有按预期工作.第一次左键单击按钮时,没有任何反应,尽管我可以看到视图模型上的 IsOpen 必须正确更新的属性.

I am attempting to do this by binding the IsOpen property of the context menu to the view model, but this is not working as expected. On first left click of the button, nothing happens, although I can see the property on the view model that IsOpen is bound to being updated correctly.

如果我右键单击,菜单会正确显示,然后如果我左键单击菜单也会显示.

If I right click, the menu will display correctly, and after this if I left click the menu will also show.

有没有人见过这个,或者对我需要做什么才能在 IsOpen 属性更新时打开 contextMenu 有任何想法?

Has anyone ever seen this or have any ideas on what I need to do to get the contextMenu to open when the IsOpen property is updated?

XAML

<Window x:Class="PopUpTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mvp="clr-namespace:PopUpTest"
    Title="MainWindow" Height="350" Width="525" x:Name="This">
<Window.DataContext>
    <mvp:MainWindowViewModel />
</Window.DataContext>
<Grid>
    <Grid.Resources>
        <ContextMenu x:Key="Menu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" IsOpen="{Binding PopupViewModel.IsOpen, Mode=TwoWay}">
            <MenuItem Header="Delete" />
        </ContextMenu>
    </Grid.Resources>

    <Button Command="{Binding DisplayPopupCommand}" ContextMenu="{StaticResource Menu}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"/>
</Grid>

背后的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.Commands;

namespace PopUpTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

public class MainWindowViewModel : BaseViewModel
{
    private readonly PopupViewModel<ChildViewModel> _popupViewModel;
    private readonly DelegateCommand _displayPopupCommand;

    public MainWindowViewModel()
    {
        _popupViewModel = new PopupViewModel<ChildViewModel>(new ChildViewModel { FirstName = "John", LastName = "Doe" });
        _displayPopupCommand = new DelegateCommand(() => { PopupViewModel.IsOpen = PopupViewModel.IsOpen == false; Console.WriteLine(PopupViewModel.IsOpen); });
    }

    public ICommand DisplayPopupCommand
    {
        get { return _displayPopupCommand; }
    }

    public PopupViewModel<ChildViewModel> PopupViewModel
    {
        get { return _popupViewModel; }
    }
}

public class PopupViewModel<T> : BaseViewModel
{
    private readonly T _data;

    public PopupViewModel(T data)
    {
        _data = data;
    }

    public T Data
    {
        get { return _data; }
    }

    private bool _isOpen;
    public bool IsOpen
    {
        get { return _isOpen; }
        set
        {
            if (_isOpen != value)
            {
                _isOpen = value;
                OnPropertyChanged("IsOpen");
            }
        }
    }
}

public class ChildViewModel : BaseViewModel
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName != value)
            {
                _firstName = value;
                OnPropertyChanged("FirstName");
            }
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (_lastName != value)
            {
                _lastName = value;
                OnPropertyChanged("LastName");
            }
        }
    }

}

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
}

推荐答案

我已经能够通过将 BindingProxy 引入 XAML 来解决这个问题,如 MSDN 论坛上这篇文章的回答中所述:

I have been able to solve this by introducing a BindingProxy to the XAML as described in the answer to this post on the MSDN forums:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/a4149979-6fcf-4240-a172-66122225d7bc/wpf-mvvm-contextmenu-binding-isopen-to-view-model?forum=wpf

绑定代理解决了 ContextMenu 在右键单击后首次显示之前没有 DataContext 的问题.

The binding proxy gets around the issue where the ContextMenu does not have a DataContext until it first displays after a right click.

这里进一步讨论了这个问题:http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

The issue is discussed further here: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

这篇关于WPF MVVM ContextMenu 绑定 IsOpen 到模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆