listboxitem的上下文菜单绑定到observablecollection MVVM样式

时间:2012-05-16 12:35:16

标签: wpf xaml listbox contextmenu observablecollection

我有3个列表框,它们绑定了两个相同类型的3个独立的可观察集合。我的ViewModel具有通过属性公开的可观察集合。这是针对一些拖放分组,源列表框可以将项目拖动到两个不同的列表中。但我想让用户能够右键单击listboxitem并设置项目的属性。类型,名称等等。我正在使用数据模板,因为我希望所有三个框在功能上都相同。这很好用,当我点击单个项目没有问题时,我可以弹出上下文菜单。我的麻烦是我有一个名为FieldType的属性。这是一个有4个潜在价值的枚举。我不能,为了我的生活,弄清楚如何将MenuItem的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>

在上面的代码中,您可以看到String,Date和Barcode MenuItems我正在尝试做什么(得到爱的代码,这是一个正在进行的工作)。我的问题是它应该调用的公开属性。我不知道在我的ViewModel属性中如何获取observable集合中与所单击项目对应的项目。我有一个值转换器EnumToBoolean,它将位于绑定上以获取是否进行检查。问题是在可观察集合中设置/获取该特定项目的属性。

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

由于 布莱斯

编辑: 我使用Angel的建议尝试了以下内容......

        <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 vs TextBox问题?您在示例中使用了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:无法找到引用'ElementName = Field'的绑定源。 BindingExpression :(没有路径);的DataItem = NULL; target元素是'ContextMenu'(Name =''); target属性是'PlacementTarget'(类型'UIElement')

所以看起来绑定不起作用。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

ContextMenu不是视觉树的一部分。因此,默认情况下,它不会将\ bind连接到应用它的TextBlock的datacontext ...

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

  1. 设置ContextMenu.PlacementTarget并将其作为单个MenuItem绑定中的Path引用。
  2. e.g。

       <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>
    

    所以在上面的例子中......你想要连接菜单项和文本框的数据上下文。因此,您需要在PlacementTarget上定义ContextMenu。此展示位置定位只能使用两种类型的绑定设置... ElementNameStaticResource。一旦上下文菜单通过PlacementTarget连接到可视元素,请使用meuitem绑定中的Path来解析数据上下文属性,即MyHeader

    OR

    使用代理元素方法......

    Bind datagrid column visibility MVVM