绑定到可观察集合 MVVM 样式的列表框项的上下文菜单



>我有 3 个列表框,都绑定了两个相同类型的 3 个独立可观察集合。 我的视图模型具有通过属性公开的可观察集合。 这是为了一些拖放分组,源列表框可以将项目拖动到两个不同的列表上。 但我想让用户能够右键单击列表框项并设置该项的属性。 诸如类型、名称等内容。 我正在使用数据模板,因为我希望所有三个框在功能上都相同。 这效果很好,当我单击单个项目时,我可以毫无问题地弹出上下文菜单。 我的麻烦是我有一个名为FieldType的财产。 它是一个具有 4 个潜在值的枚举。 我一辈子都无法弄清楚如何将菜单项的 IsChecked 属性绑定到该属性......反正功能上。 这是我尝试过的...

<DataTemplate x:Key="SFTemplateWithContextMenu">
        <TextBlock Text="{Binding Path=FieldName}" ><!--Tag="{Binding DataContext, ElementName=Window}"-->
         <TextBlock.ContextMenu>
                <ContextMenu >
                    <ContextMenu.Resources>
                        <Configurator:EnumToBooleanConverter x:Key="EnumToBooleanConverterc" />
                    </ContextMenu.Resources>
                    <MenuItem  Header="Rename..." />
                    <MenuItem Header="Field Type">
                        <MenuItem.Resources>
                            <Configurator:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
                        </MenuItem.Resources>
                        <MenuItem  Header="String" IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=DataContext.FieldType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource EnumToBooleanConverterc}, ConverterParameter={x:Static Configurator:TypeDesc.String}, PresentationTraceSources.TraceLevel=High}"/>
                        <MenuItem  Header="Date" IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=DataContext.FieldType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Configurator:TypeDesc.Date}}"/>
                        <MenuItem  Header="Barcode" IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=DataContext.FieldType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Configurator:TypeDesc.BarCode}}" />
                    </MenuItem>
                </ContextMenu> 
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>

在上面的代码中,您可以在字符串,日期和条形码菜单项上看到我正在尝试执行的操作(必须喜欢正在进行的代码(。 我的问题是它应该调用的公开属性。 我不知道如何在我的 ViewModel 属性中访问可观察集合中与单击的项目对应的项目。 我有一个值转换器 EnumToBoolean,它将位于绑定上以检查或不检查。 问题是在可观察集合中设置/获取该特定项的属性。

有什么想法吗? 需要更多代码? 需要我澄清什么吗? 我离得有多近? 顺便说一下,ViewModel 代码是用 VB 2010 编写的。

谢谢布莱斯

编辑:我已经使用安吉尔的建议尝试了以下内容......

        <DataTemplate x:Key="SFTemplateWithContextMenu">
        <TextBlock x:Name="Field" Text="{Binding Path=FieldName}" >
         <TextBlock.ContextMenu PlacementTarget="{Binding ElementName=Field}">
                    <MenuItem  Header="Rename..." />
                    <MenuItem Header="Field Type">
                        <MenuItem.Resources>
                            <Configurator:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
                        </MenuItem.Resources>
                        <MenuItem  Header="Date" IsCheckable="True" IsChecked="{Binding PlacementTarget.DataContext.FieldType, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Configurator:TypeDesc.String}, PresentationTraceSources.TraceLevel=High}"/>
                    </MenuItem>
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>

但这给了我一个错误,说...无法设置属性元素的属性。 不确定这是否是 TextBlox 与 TextBox 的问题? 您在示例中使用了文本框...我的猜测是你的代码也会做同样的事情。 所以我随后尝试了以下方法...

        <DataTemplate x:Key="SFTemplateWithContextMenu">
        <TextBlock x:Name="Field" Text="{Binding Path=FieldName}" ><!--Tag="{Binding DataContext, ElementName=Window}"-->
         <TextBlock.ContextMenu>
                <ContextMenu PlacementTarget="{Binding ElementName=Field}" >
                    <MenuItem  Header="Rename..." />
                    <MenuItem Header="Field Type">
                        <MenuItem.Resources>
                            <Configurator:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
                        </MenuItem.Resources>
                        <MenuItem  Header="Date" IsCheckable="True" IsChecked="{Binding PlacementTarget.DataContext.FieldType, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Configurator:TypeDesc.String}, PresentationTraceSources.TraceLevel=High}"/>
                    </MenuItem>
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>

但这会导致绑定错误...System.Windows.Data 错误:4:找不到引用"元素名称=字段"的绑定源。绑定表达式:(无路径(;数据项=空;目标元素是"上下文菜单"(名称="(;目标属性为"放置目标"(类型为"UIElement"(

因此,绑定似乎不起作用。有什么想法吗?

ContextMenu不是可视化树的一部分。因此,默认情况下,它不会将\绑定连接到应用它的文本块的数据上下文...

所以有 2 种方法可以做到这一点...

  1. 设置ContextMenu.PlacementTarget并将其称为单个菜单项绑定中的Path

例如

   <TextBox x:Name="MyTextBlock">
        <TextBox.ContextMenu PlacementTarget="{Binding ElementName=MyTextBlock}">
            <MenuItem 
                 Header="{Binding PlacementTarget.DataContext.MyHeader, 
                                  RelativeSource={RelativeSource
                                      AncestorType={x:Type ContextMenu}}}"
        </TextBox.ContextMenu>
  </TextBox>

所以在上面的例子中...您希望将菜单项与文本框的数据上下文连接起来。所以你在ContextMenu上定义PlacementTarget.此放置目标只能使用 2 种类型的绑定进行设置... ElementNameStaticResource.一旦上下文菜单通过PlacementTarget连接到可视元素,使用 meuitem 绑定中的Path来解析数据上下文属性,即 MyHeader .

使用代理元素方法...

绑定数据网格列可见性 MVVM

最新更新