WPF:菜单项仅绑定命令参数一次

发布于 2024-09-04 15:16:38 字数 1963 浏览 10 评论 0 原文

在使用带有命令的菜单时,我已经注意到这一点好几次了,它们不是很动态,请检查一下。我正在从颜色集合创建一个菜单,我用它来为数据网格中的列着色。无论如何,当我第一次调出菜单(它是上下文菜单)时,命令参数绑定就会发生,并且它绑定到打开上下文菜单的列。然而,下次我提出它时,wpf 似乎缓存了菜单,并且它不会重新绑定命令参数。所以我只能在上下文菜单出现的初始列上设置颜色。

我过去曾通过使菜单完全动态化并在菜单关闭时销毁集合并在下次打开时强制重建来解决这种情况,我不喜欢这种黑客行为。有人有更好的方法吗?

    <MenuItem
       Header="Colour"
       ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ResultEditorGrid}}, Path=ColumnColourCollection}"
       ItemTemplate="{StaticResource colourHeader}" >
       <MenuItem.Icon>
          <Image
             Source="{StaticResource ColumnShowIcon16}" />
       </MenuItem.Icon>
       <MenuItem.ItemContainerStyle>
          <Style
             TargetType="MenuItem"
             BasedOn="{StaticResource systemMenuItemStyle}">
             <!--Warning dont change the order of the following two setters
                                otherwise the command parameter gets set after the command fires,
                                not mush use eh?-->
             <Setter
                Property="CommandParameter">
                <Setter.Value>
                   <MultiBinding>
                      <MultiBinding.Converter>
                         <local:ColumnAndColourMultiConverter/>
                      </MultiBinding.Converter>
                      <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGridColumnHeader}}" Path="Column"/>
                      <Binding Path="."/>
                   </MultiBinding>
                </Setter.Value>
             </Setter>
             <Setter
                Property="Command"
                Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ResultEditorGrid}}, Path=ColourColumnCommand}" />
          </Style>
       </MenuItem.ItemContainerStyle>
    </MenuItem>

Ive noticed this a couple of times when using menus with commands, they are not very dynamic, check this out. I am creating a menu from a collection of colours, I use it to colour a column in a datagrid. Anyway when i first bring up the menu (its a context menu) the command parameter binding happens and it binds to the column that the context menu was opened on. However the next time i bring it up it seems wpf caches the menu and it doesnt rebind the command parameter. so i can set the colour only on the initial column that the context menu appeared on.

I have got around this situation in the past by making the menu totally dynamic and destroying the collection when the menu closed and forcing a rebuild the next time it opened, i dont like this hack. anyone got a better way?

    <MenuItem
       Header="Colour"
       ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ResultEditorGrid}}, Path=ColumnColourCollection}"
       ItemTemplate="{StaticResource colourHeader}" >
       <MenuItem.Icon>
          <Image
             Source="{StaticResource ColumnShowIcon16}" />
       </MenuItem.Icon>
       <MenuItem.ItemContainerStyle>
          <Style
             TargetType="MenuItem"
             BasedOn="{StaticResource systemMenuItemStyle}">
             <!--Warning dont change the order of the following two setters
                                otherwise the command parameter gets set after the command fires,
                                not mush use eh?-->
             <Setter
                Property="CommandParameter">
                <Setter.Value>
                   <MultiBinding>
                      <MultiBinding.Converter>
                         <local:ColumnAndColourMultiConverter/>
                      </MultiBinding.Converter>
                      <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGridColumnHeader}}" Path="Column"/>
                      <Binding Path="."/>
                   </MultiBinding>
                </Setter.Value>
             </Setter>
             <Setter
                Property="Command"
                Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ResultEditorGrid}}, Path=ColourColumnCommand}" />
          </Style>
       </MenuItem.ItemContainerStyle>
    </MenuItem>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

离旧人 2024-09-11 15:16:38

问题是 ContextMenu 的 显然是它们自己的视觉树的根 我在某处读到它将 datacontext 作为其父级,但是仅在加载时一次,因此如果父数据上下文更改,菜单项不会更改。 (不幸的是,我找不到正确的链接)

我以前遇到过这个问题,我所做的是使用 Josh Smith 的虚拟分支模式。这是相当技术性的,但这篇文章帮助我很好地理解了这个视觉树的废话是怎么回事。

本质上,您创建了这个绑定到视图数据上下文的桥。该桥被创建为静态资源,允许您从上下文菜单绑定到它,即使它位于可视化树之外。

将其添加到您的 xaml 中:

<Window.Resources>
   <!-- This is the "root node" in the virtual branch
   attached to the logical tree. It has its
   DataContext set by the Binding applied to the
   Window's DataContext property. -->
   <FrameworkElement x:Key="DataContextBridge" />
</Window.Resources>

<Window.DataContext>
   <!-- This Binding sets the DataContext on the "root node"
   of the virtual logical tree branch.  This Binding
   must be applied to the DataContext of the element
   which is actually assigned the data context value. -->
   <Binding
    Mode="OneWayToSource"
    Path="DataContext"
    Source="{StaticResource DataContextBridge}"
   />
</Window.DataContext>

这是我谈到的桥梁。它获取数据上下文并将其推送到桥接数据上下文,这是(正如我之前所说的)静态资源。

然后,您只需将其添加到上下文菜单的数据上下文:

 DataContext="{Binding
               Source={StaticResource DataContextBridge},
               Path=DataContext}"

现在丢弃所有相对路径等并在菜单项内使用常规绑定,您应该没问题。数据上下文将照常更新。

请注意:

显然,您必须在数据上下文中拥有某些属性才能辨别要使用哪个命令,但我相信您可以弄清楚。该解决方案仅处理上下文菜单不更新的方式

The problem is that ContextMenu's are apparently the root of their own visual tree I read somewhere that it takes the datacontext its parent, but only once on loading, so if the parents datacontext changes the menuitems does not. (unfortunately I can't find a link for that right not)

I have encountered this problem before, and what I did was use Josh Smith's Virtual Branch Pattern. It's fairly technical but the article helped me understand really well what was going on with this visual tree nonsense.

Essentially you create this bridge that binds to the view's datacontext. The bridge is created as a static resource, allowing you to bind to it from the context menu even if it is outside the visual tree.

Add this to your xaml:

<Window.Resources>
   <!-- This is the "root node" in the virtual branch
   attached to the logical tree. It has its
   DataContext set by the Binding applied to the
   Window's DataContext property. -->
   <FrameworkElement x:Key="DataContextBridge" />
</Window.Resources>

<Window.DataContext>
   <!-- This Binding sets the DataContext on the "root node"
   of the virtual logical tree branch.  This Binding
   must be applied to the DataContext of the element
   which is actually assigned the data context value. -->
   <Binding
    Mode="OneWayToSource"
    Path="DataContext"
    Source="{StaticResource DataContextBridge}"
   />
</Window.DataContext>

This is the bridge I spoke of. It takes the datacontext and __pushes it_ to to the bridges datacontext, which is (as I said before) a static resource.

Then you simply this to the contextmenu's datacontext:

 DataContext="{Binding
               Source={StaticResource DataContextBridge},
               Path=DataContext}"

Now throw away all the relative pathing etc and use regular binding inside the menu items, and you should be fine. The datacontext will update as usual.

Just one note:

You will obviously have to have some property in the datacontext to discern which command to use, but i'm sure you can figure it out. This solution just deals with the way contextmenu's dont update

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文