使用不同的DataContexts重用ContextMenu

时间:2014-02-21 18:22:27

标签: wpf xaml contextmenu

我正在尝试为数组的每个元素创建一个可重用的ContextMenu,如下所示:

<ContextMenu>
    <ContextMenu.Resources>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Command" Value="{Binding UpdateFooInfoCommand}"/>
            <Setter Property="CommandParameter" Value="{Binding  MyViewModel.FooInfo[0]}" />
        </Style>
    </ContextMenu.Resources>

    <MenuItem 
        Header="Blocked" 
        IsEnabled="{Binding MyViewModel.FooInfo[0].CurrentlyEnabled, Converter={StaticResource ContainsValueConverter}, ConverterParameter={x:Static entities:FooStatus.Blocked}}" 
        IsChecked="{Binding MyViewModel.FooInfo[0].CurrentlySelected, Mode=TwoWay, Converter={StaticResource ContainsValueConverter}, ConverterParameter={x:Static entities:FooStatus.Blocked}}" 
    />
    <MenuItem 
        Header="Working" 
        IsEnabled="{Binding MyViewModel.FooInfo[0].CurrentlyEnabled, Converter={StaticResource ContainsValueConverter}, ConverterParameter={x:Static entities:FooStatus.Working}}" 
        IsChecked="{Binding MyViewModel.FooInfo[0].CurrentlySelected, Mode=TwoWay, Converter={StaticResource ContainsValueConverter}, ConverterParameter={x:Static entities:FooStatus.Working}}" 
    />
    <MenuItem 
        Header="Sleeping" 
        IsEnabled="{Binding MyViewModel.FooInfo[0].CurrentlyEnabled, Converter={StaticResource ContainsValueConverter}, ConverterParameter={x:Static entities:FooStatus.Sleeping}}" 
        IsChecked="{Binding MyViewModel.FooInfo[0].CurrentlySelected, Mode=TwoWay, Converter={StaticResource ContainsValueConverter}, ConverterParameter={x:Static entities:FooStatus.Sleeping}}" 
    />
</ContextMenu>

使用:

[Flags]
public enum FooStatus : byte
{
    None = 0,
    Sleeping = 1 << 0,
    Working = 1 << 1,
    Blocked = 1 << 4
}

但是你可以看到我在任何地方使用数组,所以没有办法重用这个contextMenu但是使用copy&amp;粘贴和更改索引,为了避免有很多数组引用,我尝试了这个:

<ContextMenu DataContext="{Binding PlacementTarget.DataContext.MyViewModel.FooInfo[0], RelativeSource={RelativeSource Self}}">
    <ContextMenu.Resources>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Command" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type Control}, Mode=FindAncestor, AncestoLevel=2}, Path=DataContext.UpdateFooInfoCommand }" />
            <Setter Property="CommandParameter" Value="{Binding}" />
        </Style>
    </ContextMenu.Resources>
    .....
</ContextMenu> 

这让我获得了datacontext,因此我不再需要在任何地方引用该数组,但我仍然迷失在如何使命令像以前一样工作并将此资源存储为多个用法并且只是更改datacontext。

修改

<ContextMenu DataContext="{Binding PlacementTarget.DataContext.MyViewModel.FooInfo[0], RelativeSource={RelativeSource Self}}"
              Tag="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
    <ContextMenu.Resources>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Command" Value="{Binding  RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}, Path=Tag.UpdateFooInfoCommand}"/>
            <Setter Property="CommandParameter" Value="{Binding}" />
        </Style>
    </ContextMenu.Resources>
    .....
</ContextMenu>

我找到了关于PlacementTarget的方式,不知道contextmenu不是树的一部分 但我仍然不清楚如何模拟这个上下文菜单

1 个答案:

答案 0 :(得分:0)

我使用转换器来处理类似的情况;这种方法可能对你有用。也许是这样的:

 public class FooInfoContextMenueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var foo = value as FooInfo;
        if (foo!=null)
        {
            var blocked = new MenueItem(){ Header = "Blocked" };
            //Set up bindings ...

            var working = new MenueItem(){ Header = "Working" };
            //Set up bindings ...

            var sleeping = new MenueItem(){ Header = "Sleeping" };
            //Set up bindings...

            return new[] { blocked, working, sleeping };
        }
        return null;
    }
}

您可以在(例如)DataTemplate中使用它,如下所示:

<DataTemplate.Resources>
    <foo:FooInfoContextMenueConverter x:Key="fooInfoConv">
</DataTemplate.Resources>
...
<ContextMenu ItemsSource="{Binding Converter={StaticResource fooInfoConv}}" />