WPF MVVM ContextMenu将IsOpen绑定到模型
本文关键字:绑定 模型 IsOpen MVVM ContextMenu WPF | 更新日期: 2023-09-27 17:57:25
我有一个与上下文菜单关联的按钮。我可以右键单击该按钮并显示上下文菜单,正如您所期望的那样,但我希望能够在另一个事件之后显示上下文菜单。例如,左键单击或拖放式事件。
我试图通过将上下文菜单的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));
}
}
}
我已经能够通过向XAML引入BindingProxy来解决这个问题,如MSDN论坛上这篇文章的答案所述:
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/