WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参

ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataContext,所以如果要绑定父级的DataContext,直接DataContext=“{Binding}”是行不通的

不能绑父级,但是能绑资源

第一步:定义一个中间类用来做资源对象

复制代码
 1 public class BindingProxy : Freezable
 2     {
 3         #region Overrides of Freezable
 4 
 5         protected override Freezable CreateInstanceCore()
 6         {
 7             return new BindingProxy();
 8         }
 9 
10         #endregion
11 
12         public object Data
13         {
14             get { return (object)GetValue(DataProperty); }
15             set { SetValue(DataProperty, value); }
16         }
17 
18         public static readonly DependencyProperty DataProperty =
19             DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
20     }
复制代码

第二步:引用命名空间,在控件中定义资源

1 <UserControl.Resources>
2         <libBinding:BindingProxy x:Key="BindingProxy" Data="{Binding}"/>
3     </UserControl.Resources>

第三步:绑定ContextMenu、MenuItem

(Button.Command 和 ContextMenu.IsOpen 的绑定部分可以不关注,这两个绑定是用来控制ContextMenu打开的)

复制代码
 1 <Button Command="{Binding Customfold}">
 2             <Button.ContextMenu>
 3                 <ContextMenu DataContext="{Binding Data,Source={StaticResource BindingProxy}}"  
 4                              ItemsSource="{Binding ItemModelCollection}"
 5                              IsOpen="{Binding OpenCustomfold,Mode=OneWay}">
 6                     <ContextMenu.ItemContainerStyle>
 7                         <Style TargetType="MenuItem">
 8                             <Setter Property="Header" Value="{Binding ...}"/>
 9                             <Setter Property="Command" Value="{Binding ...}"/>
10                             <Setter Property="CommandParameter" Value="{Binding ...}"/>
11                         </Style>
12                     </ContextMenu.ItemContainerStyle>
13                 </ContextMenu>
14             </Button.ContextMenu>
15             <Image .../>
16         </Button>
复制代码

第四步:传递参数

ContextMenu是它自身视觉树的根节点,所以即使通过RelativeSource.FindAncestor也找不到要传递的参数。

解决:可以通过PlacementTarget解决。微软对PlacementTarget的解释是:获取或设置UIElement,当它打开时相对于它确定ContextMenu的位置。应该可以理解为放置此ContextMenu的UIElement。

 1 CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}, Path=PlacementTarget}"  

如果要传递Item,如ListBox的SelectedItem:

 1 CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"  

参考:

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

http://stackoverflow.com/questions/1580753/wpf-contextmenu-with-itemssource-how-to-bind-to-command-in-each-item

posted @   Walter0527  阅读(7993)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示