_wpf 点击menui">
当前位置:   article > 正文

WPF解决ContextMenu菜单的DataContext无法绑定,并实现按钮左键弹出菜单_wpf 点击menuitem不能绑定命定

wpf 点击menuitem不能绑定命定

问题一

当为ContextMenu指定DataContext时,因为ContextMenu属于弹出层,在VisualTree中与所在的设计视图已经分离,所以无法将DataContext绑定到任何父级元素,即使整个视图已指定了DataContext,也无法设置MenuItem的Command,也就是说,以下几种方式都是无效的,均不能触发菜单项的Command

  1. <UserControl x:Class="....."
  2. x:Name="TestView">
  3. <Grid>
  4. <Button Content="测试菜单-继承DataContext">
  5. <Button.ContextMenu>
  6. <ContextMenu>
  7. <MenuItem Header="菜单项1" Command="{Binding Test1}"/>
  8. <MenuItem Header="菜单项2" Command="{Binding Test2}"/>
  9. </ContextMenu>
  10. </Button.ContextMenu>
  11. </Button>
  12. <Button Content="测试菜单-指定DataContext"
  13. DataContext="{Binding ElementName=TestView}">
  14. <Button.ContextMenu>
  15. <ContextMenu>
  16. <MenuItem Header="菜单项1" Command="{Binding Test1}"/>
  17. <MenuItem Header="菜单项2" Command="{Binding Test2}"/>
  18. </ContextMenu>
  19. </Button.ContextMenu>
  20. </Button>
  21. <Button Content="测试菜单-指定菜单项的DataContext">
  22. <Button.ContextMenu>
  23. <ContextMenu>
  24. <MenuItem Header="菜单项1" Command="{Binding Test1, ElementName=TestView}"/>
  25. <MenuItem Header="菜单项2" Command="{Binding Test2, ElementName=TestView}"/>
  26. </ContextMenu>
  27. </Button.ContextMenu>
  28. </Button>
  29. <Button Content="测试菜单-绑定动态DataContext"
  30. DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}">
  31. <Button.ContextMenu>
  32. <ContextMenu>
  33. <MenuItem Header="菜单项1" Command="{Binding Test1}"/>
  34. <MenuItem Header="菜单项2" Command="{Binding Test2}"/>
  35. </ContextMenu>
  36. </Button.ContextMenu>
  37. </Button>
  38. </Grid>
  39. </UserControl>

  问题1可以参考博客园的一个帖子,使用BindingProxy实现代理绑定上下文:https://www.cnblogs.com/muran/p/6702444.html,这里介绍的是从Button本身优化的方式,更容易理解,也较为直接

问题二

通常将ContextMenu赋值给UIElement对象时,都是作为右键菜单,但某些应用场景希望能通过点击鼠标左键弹出菜单。

问题二也可以在按钮的Click事件上进行处理,主动使它弹出菜单,但缺点是每个按钮都要写同样的处理逻辑,违反了单一职责原则和迪米特法则,简单讲就是麻烦和不易维护。

 

解决方案

重写Button,其他有意义的扩展也可以加入到同一个重写的类中,比如 Button.Key,Button.IsChecked属性等

后端代码

  1. namespace MenuDemo.Controls
  2. {
  3. public class AppButton : Button
  4. {
  5. //注册Menu依赖属性
  6. public ContextMenu Menu
  7. {
  8. get { return (ContextMenu)GetValue(MenuProperty); }
  9. set { SetValue(MenuProperty, value); }
  10. }
  11. public static readonly DependencyProperty MenuProperty =
  12. DependencyProperty.Register("Menu", typeof(ContextMenu), typeof(AppButton), new PropertyMetadata(null, Menu_PropertyChanged));
  13. //处理Menu属性变更
  14. private static void Menu_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  15. {
  16. var button = d as SmartButton;
  17. var menu = e.NewValue as ContextMenu;
  18. if (menu != null && menu.DataContext == null && menu.GetBindingExpression(DataContextProperty) == null)
  19. {
  20. //当未使用其他方式指定ContextMenu的DataContext时,使其与Button的DataContext一致
  21. menu.DataContext = button.DataContext;
  22. }
  23. }
  24. //重写点击时执行的方法
  25. protected override void OnClick()
  26. {
  27. base.OnClick();
  28. if (this.Menu != null)
  29. {
  30. //弹出菜单
  31. this.Menu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
  32. this.Menu.PlacementTarget = this;
  33. this.Menu.IsOpen = true;
  34. }
  35. }
  36. }
  37. }

前端代码

  1. <UserControl x:Class="......"
  2. xmlns:controls="MenuDemo.Controls">
  3. <Grid>
  4. <controls:AppButton Content="开始" DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}">
  5. <controls:AppButton.Menu>
  6. <ContextMenu>
  7. <MenuItem Header="测试1" Command="{Binding Test1}"/>
  8. <MenuItem Header="测试2" Command="{Binding Test2}"/>
  9. </ContextMenu>
  10. </controls:AppButton.Menu>
  11. </controls:AppButton>
  12. </Grid>
  13. </UserControl>

这样通过前端赋值Menu时处理其DataContext的方式,使ContextMenu与Button的上下文保持一致,既解决了无法绑定上下文的问题,又可以实现左键点击弹出。

如果UserControl的代码中设置了 DataContext = this,可以省去为AppButton绑定DataContext的过程,但需要在Menu_PropertyChanged中进行额外处理,这里不再赘述。

如有不当之处,欢迎指出。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/493441
推荐阅读
相关标签
  

闽ICP备14008679号