WPF MVVM ContextMenu将IsOpen绑定到Model

时间:2014-04-08 09:27:02

标签: c# wpf mvvm

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

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

如果我右键单击,菜单将正确显示,此后如果我左键单击,菜单也会显示。

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

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));
    }
}
}

1 个答案:

答案 0 :(得分:7)

我已经能够通过在MSDN论坛上的这篇文章的答案中描述的向XAML引入BindingProxy来解决这个问题:

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的问题。

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

相关问题