绑定在datatemplate中定义的命令

时间:2012-07-27 21:11:12

标签: wpf xaml binding command

我知道这个主题的答案很少。但是他们都没有在我的案件中工作。

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

这是ListView:

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

3 个答案:

答案 0 :(得分:0)

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

看起来你是在ListBox级别(或LayoutRoot?)上实现命令。将上下文菜单放在ListBox上可能更容易,并使用ListBox.SelectedItem查找当前选择并在其上应用逻辑。

答案 1 :(得分:0)

您可以使用RelativeSource:

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

答案 2 :(得分:0)

在这种情况下,您可能应该使用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/