【问题标题】:Binding a command defined in a datatemplate绑定数据模板中定义的命令
【发布时间】:2012-07-26 14:21:23
【问题描述】:

我知道关于这个话题的答案很少。但它们都不适用于我的情况。

我有一个带有样式的ListView 和一个ItemContainerStyle。在ItemContainerStyle 中,我定义了一些触发器以便使用不同的DataTemplate,具体取决于是否选择了列表中的项目。然后,最后在Datatemplate 我有一个带有命令的上下文菜单。问题是如何将命令绑定到视图模型。

这是列表视图:

    <ListView
        x:Name="lstPersons"
        Grid.Row="1"
        Style="{StaticResource ListViewStyle}"
        ItemContainerStyle="{StaticResource ItemContainerStyle}"
        DataContext="{Binding}"
        ItemsSource="{Binding Path=Persons}"
        Tag="{Binding}"
        SelectedItem="{Binding Path=SelectedPerson, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    </ListView>

这些是样式、数据模板和上下文菜单(在资源字典中定义)。 上下文菜单中的命令不起作用....:

    <ContextMenu x:Key="SelectedItemContextMenu">
        <MenuItem
            Header="Do Something"
            Command="{Binding Path=DataContext.DoSomethingCmd, ElementName=LayoutRoot}">
        </MenuItem>
        <MenuItem
            Header="Do Something"
            Command="{Binding PlacementTarget.Tag.DoSomethingCmd, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
        </MenuItem>
    </ContextMenu>

<DataTemplate
    x:Key="ItemTemplate">
    <Canvas
        Margin="4"
        Width="60"
        Height="60"
        Background="LightGray">
        <TextBlock
            Foreground="Black"
            Margin="2 0 0 0"
            Opacity="0.5"
            FontFamily="Segoe UI"
            Text="{Binding Path=FirstName}" />
    </Canvas>
</DataTemplate>

<DataTemplate
    x:Key="ItemSelectedTemplate">
    <Grid>
        <Border
            BorderBrush="Black"
            BorderThickness="1"
            Margin="3"
            ContextMenu="{DynamicResource SelectedItemContextMenu}">
            <Canvas
                Width="60"
                Height="60"
                Background="LightBlue">
                <TextBlock
                    Foreground="Black"
                    Margin="2 0 0 0"
                    Opacity="0.5"
                    FontFamily="Segoe UI"
                    Text="{Binding Path=FirstName}" />
            </Canvas>
        </Border>
    </Grid>
</DataTemplate>


<!--style of the listviewitem-->
<Style
    TargetType="{x:Type ListViewItem}"
    x:Key="ItemContainerStyle">
    <Setter
        Property="ContentTemplate"
        Value="{StaticResource ItemTemplate}" />
    <Style.Triggers>
        <Trigger
            Property="IsSelected"
            Value="True">
            <Setter
                Property="ContentTemplate"
                Value="{StaticResource ItemSelectedTemplate}" />
        </Trigger>
    </Style.Triggers>
</Style>


<!--style of the listview-->
<Style
    TargetType="{x:Type ListBox}"
    x:Key="ListViewStyle">
    <Setter
        Property="Template">
        <Setter.Value>
            <ControlTemplate
                TargetType="{x:Type ListBox}">
                <Grid>
                    <Border>
                        <ScrollViewer
                            Focusable="false">
                            <WrapPanel
                                IsItemsHost="True"
                                Orientation="Horizontal"
                                Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"/>
                        </ScrollViewer>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【问题讨论】:

  • DataContext="{Binding}" 几乎什么都不做,只是赋予它已经具有更高优先级的值。

标签: wpf xaml binding command


【解决方案1】:

您的 ContextMenu 在数据模板中使用。我将被置于“LayoutRoot”的不同名称范围内,并且 ElementName 绑定将不起作用。此外,上下文菜单的 PlacementTarget 是边框,并且您没有在其上设置任何标签。所以第二个命令也不起作用。

看起来您正在 ListBox 级别(或 LayoutRoot?)上实现命令。将上下文菜单放在 ListBox 上可能会更容易,然后使用 ListBox.SelectedItem 查找当前选择并将您的逻辑应用到它上面。

【讨论】:

    【解决方案2】:

    你可以使用RelativeSource:

      <ContextMenu x:Key="SelectedItemContextMenu">
                <MenuItem
                Header="Do Something"
                Command="{Binding Path=DataContext.DoSomethingCmd, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
                </MenuItem>           
            </ContextMenu>
    

    【讨论】:

    • 不工作.. H.B 是对的——我想这不是摆脱 ContextMenu 的方法
    【解决方案3】:

    在这种情况下,您可能应该使用 RoutedCommands 而不是 VM 命令。您可以将 RoutedCommand 绑定到 ContextMenu,并且由于您只需要静态对象引用,因此找到它们应该不是问题。然后,您将在应该处理命令的控件上设置适当的 CommandBindings(ListView 或 ListViewItem,具体取决于您希望 List-ViewModel 还是 Item-ViewModel 来处理命令)。这些控件将知道它们的 ViewModel,因此绑定到它们不会有问题。通过 WPF 内置的命令路由过程,上下文菜单会自动为其命令找到合适的目标。

    有关如何以对 MVVM 友好的方式设置 CommandBindings 的指导,您可能需要参考 http://wpfglue.wordpress.com/2012/05/07/commanding-binding-controls-to-methods/

    【讨论】:

      猜你喜欢
      • 2010-12-28
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多