ใช้ ContextMenu ซ้ำกับ DataContexts ที่แตกต่างกัน

ฉันกำลังพยายามสร้าง 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 นี้ซ้ำได้ แต่ใช้การคัดลอกและวางและเปลี่ยนดัชนี เพื่อหลีกเลี่ยงไม่ให้มีการอ้างอิงอาร์เรย์จำนวนมาก ฉันลองทำสิ่งนี้:

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

นั่นทำให้ฉันมีบริบทข้อมูลดังนั้นฉันจึงไม่จำเป็นต้องอ้างอิงอาร์เรย์ทุกที่อีกต่อไป แต่ฉันยังคงหลงลืมวิธีทำให้คำสั่งทำงานเหมือนเมื่อก่อนและจัดเก็บทรัพยากรนี้สำหรับการใช้งานหลายครั้งและเพียงแค่เปลี่ยนบริบทข้อมูล

แก้ไข

<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 ไม่รู้ว่าเมนูบริบทไม่ได้เป็นส่วนหนึ่งของแผนผัง แต่ฉันยังไม่มีเบาะแสเกี่ยวกับวิธีการสร้างเมนูบริบทนี้


person elios264    schedule 21.02.2014    source แหล่งที่มา
comment
คุณสามารถสร้างเทมเพลต ContextMenue ได้โดยใส่ไว้ใน DataTemplate สำหรับเป้าหมาย หรือใน Style สำหรับ (เช่น) ListViewItem หรือสิ่งที่คุณมี แน่นอน หากคุณทำเช่นนั้น คุณจะเลิกสนใจว่ารายการปัจจุบันจะอยู่ในตำแหน่งใดในอาร์เรย์ของคุณ เพราะคุณสามารถเชื่อมโยงกับรายการปัจจุบันได้อย่างง่ายดาย   -  person mcwyrm    schedule 22.02.2014


คำตอบ (1)


ฉันใช้ตัวแปลงเพื่อจัดการกับสถานการณ์ที่คล้ายกัน แนวทางนั้นอาจใช้ได้ผลสำหรับคุณ บางทีอาจเป็นเช่นนี้:

 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}}" />
person mcwyrm    schedule 21.02.2014