【发布时间】:2023-04-02 12:24:01
【问题描述】:
问题: 我们如何在自定义行为中访问分配给 MenuItem 的绑定命令? ContextMenu 不是可视化树的一部分,并且不会绑定,直到由于在自定义行为中被抑制而永远不会发生的单击事件。
目的 我有一个使用 Microsoft.Xaml.Behaviors 的自定义行为,旨在仅在用户单击 ListView 中的对象时显示上下文菜单。我想在访问视图标记中的引用 ICommand 时使用自定义行为修改命令参数。
代码:
自定义行为 (Microsoft.Xaml.Behaviors):
public class RightClickContextMenuBehavior : Behavior<ListView>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.ContextMenuOpening += AssociatedObject_ContextMenuOpening;
AssociatedObject.PreviewMouseRightButtonDown += AssociatedObject_PreviewMouseRightButtonDown;
AssociatedObject.PreviewMouseRightButtonUp += AssociatedObject_PreviewMouseRightButtonUp;
}
protected override void OnDetached()
{
base.OnDetached();
AssociatedObject.ContextMenuOpening -= AssociatedObject_ContextMenuOpening;
AssociatedObject.PreviewMouseRightButtonDown -=
AssociatedObject_PreviewMouseRightButtonDown;
AssociatedObject.PreviewMouseRightButtonUp -= AssociatedObject_PreviewMouseRightButtonUp;
}
private void AssociatedObject_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
//Store the click locations so that we can determine drag on mouse move.
originPoint = e.GetPosition(null);
//Grab the item from the ListView
var listViewItem = TryFindFromPoint<ListViewItem>((UIElement)sender,
e.GetPosition(AssociatedObject));
if (listViewItem == null)
return;
itemReference = listViewItem;
}
private void AssociatedObject_PreviewMouseRightButtonUp(object sender,
MouseButtonEventArgs e)
{
if (itemReference != null)
{
// Only display the context menu if the user clicked on the object
// inside the listview, not the listview itself.
var targetPosition = e.GetPosition((UIElement)itemReference);
HitTestResult hitResult = VisualTreeHelper.HitTest((UIElement)itemReference,
targetPosition);
if (hitResult != null && sender is ListView)
{
var listView = sender as ListView;
//Set the context menu's visibility flag
listView.ContextMenu.IsOpen = true;
foreach (var item in listView.ContextMenu.Items)
{
if (item is MenuItem)
{
var customMemuItem = item as MenuItem;
//Apply the item the was in our hitbox as context.
customMemuItem.CommandParameter = itemReference.DataContext;
/*
ISSUE:
Bindings here are always null, how do I force the bound
ICommand in the XAML markup to be available here. I'd like
to use the Command binding from the markup, and functionally
apply my DataContext customMemuItem.Command is null
*/
}
}
e.Handled = true; //Handle the bubble
}
}
else
{
if (sender is ListView)
{
//Hide the context menu.
var listView = sender as ListView;
listView.ContextMenu.IsOpen = false;
e.Handled = true;
}
}
}
}
查看:
<ListView Grid.Row="1"
ItemsSource="{Binding Path= ItemQueue, IsAsync=True}"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<behaviors:Interaction.Behaviors>
<commandbehaviors:RightClickContextMenuBehavior />
</behaviors:Interaction.Behaviors>
<ListView.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}}">
<MenuItem Header="Context Menu Command"
Command="{Binding Source={x:Type models:MyViewModel},
Path=BindingContext.MenuTestCommand}"
CommandParameter="{Binding}"/>
</ContextMenu>
</ListView.ContextMenu>
[...]
</ListView>
编辑#1: 我们正在使用 ListView 所在的 MVVM:
public partial class MyViewModelView : UserControl
{
public DocumentTileManagementView()
{
InitializeComponent();
}
}
public class MyViewModel : ViewModelBase
{
public MyViewModel()
{
MenuTestCommand = new ApplicationRelayCommand(MenuTestCommandBehavior);
}
public ObservableCollection<ObjectViewModel> ItemQueue
{
get
{
return _ItemQueue;
}
set
{
this.MutateVerbose(ref _ItemQueue, value, this.RaisePropertyChanged());
}
}
private ObservableCollection<MyDataObject> _ItemQueue= new ObservableCollection<MyDataObject>();
public ICommand MenuTestCommand { get; }
private async void MenuTestCommandBehavior(object obj)
{
}
}
我还没有找到一种在不允许 ListView 上的初始右键单击事件链的情况下调用绑定的方法。
我有一个可行的解决方案,我允许第一次右键单击事件并覆盖每次后续单击中的行为。我想在自定义 (Microsoft.Xaml.Behaviors) 行为中调用第一次右键单击期间发生的任何事情。
【问题讨论】:
-
MenuTestCommand和ItemQueue是否定义在同一个视图模型类中? -
两个项目都在同一个视图模型上,其中
MenuTestCommand是ICommand,Item Queue是ObservableCollection。
标签: c# wpf xaml mvvm asp.net-core-3.1