>我有 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 种方法可以做到这一点...
- 设置
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 种类型的绑定进行设置... ElementName
或StaticResource
.一旦上下文菜单通过PlacementTarget
连接到可视元素,使用 meuitem 绑定中的Path
来解析数据上下文属性,即 MyHeader
.
或
使用代理元素方法...
绑定数据网格列可见性 MVVM