Я хочу создать контекстное меню, в котором один из элементов menuItem будет подменю с выбором между значениями перечисления.
Я не хочу жестко кодировать любые значения из моего перечисления в xaml, потому что я хочу, чтобы любые изменения значения enum автоматически отражались в пользовательском интерфейсе без каких-либо вмешательств.
Я хочу, чтобы мое меню было обычным контекстным меню без какого-либо артефакта (я имею в виду, что внешний вид должен быть как обычный ContextMenu).
Я пробовал много способов без успеха. Каждое из моих пробных случаев всегда пропускает что-то, но главным образом кажется, что основная недостающая часть - это конвертер, который может быть связан с чем-то.
I красный:
- Создание настраиваемого контекстного меню из списка значений перечисления
- WPF Multibinding для просмотра модели
- Связывание с параметром конвертера
Это мои многочисленные испытания и связанный код:
<Window x:Class="WpfContextMenuWithEnum.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfContextMenuWithEnum="clr-namespace:WpfContextMenuWithEnum"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        xmlns:converter="clr-namespace:WpfContextMenuWithEnum.Converter"
        Title="MainWindow" Height="350" Width="525"
        Name="MyWindow">
    <Window.DataContext>
        <wpfContextMenuWithEnum:MainWindowModel></wpfContextMenuWithEnum:MainWindowModel>
    </Window.DataContext>
    <Window.Resources>
        <ObjectDataProvider x:Key="EnumChoiceProvider" MethodName="GetValues" ObjectType="{x:Type system:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="wpfContextMenuWithEnum:EnumChoice"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
        <converter:EnumToBooleanConverter x:Key="EnumToBooleanConverter"></converter:EnumToBooleanConverter>
        <converter:MultiBind2ValueComparerConverter x:Key="MultiBind2ValueComparerConverter"></converter:MultiBind2ValueComparerConverter>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Text="Right click me">
            <TextBox.ContextMenu>
                <ContextMenu ItemsSource="{Binding Source={StaticResource EnumChoiceProvider}}">
                    <ContextMenu.ItemTemplate>
                        <DataTemplate>
                            <MenuItem IsCheckable="True" Header="{Binding Path=.}">
                                <MenuItem.IsChecked>
                                    <MultiBinding Converter="{StaticResource MultiBind2ValueComparerConverter}">
                                        <Binding Path="DataContext.ModelEnumChoice" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" />
                                        <Binding Path="." Mode="OneWay"></Binding>
                                    </MultiBinding>
                                </MenuItem.IsChecked>
                            </MenuItem>
                        </DataTemplate>
                    </ContextMenu.ItemTemplate>
                </ContextMenu>
            </TextBox.ContextMenu>
        </TextBox>
    </Grid>
</Window>
Enum:
using System.ComponentModel;
    namespace WpfContextMenuWithEnum
    {
        public enum EnumChoice
        {
            [Description("Default")]
            ChoiceDefault = 0, // easier if the default have value = 0
            [Description("<1>")]
            Choice1 = 1,
            [Description("<2>")]
            Choice2 = 2,
        }
    }
Конвертеры:
using System;
using System.Windows;
using System.Windows.Data;
namespace WpfContextMenuWithEnum.Converter
{
    public class ConverterWrapperWithDependencyParameterConverter : DependencyObject, IValueConverter
    {
        public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register("Parameter",
            typeof(object), typeof(ConverterWrapperWithDependencyParameterConverter));
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (parameter != null)
            {
                throw new ArgumentException("The parameter should be set directly as a property not into the Binding object.");
            }
            return Converter.Convert(value, targetType, Parameter, culture);
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (parameter != null)
            {
                throw new ArgumentException("The parameter should be set directly as a property not into the Binding object.");
            }
            return Converter.ConvertBack(value, targetType, Parameter, culture);
        }
        public object Parameter
        {
            get { return GetValue(ParameterProperty); }
            set { SetValue(ParameterProperty, value); }
        }
        public IValueConverter Converter { get; set; }
    }
}
using System;
using System.Windows.Data;
namespace WpfContextMenuWithEnum.Converter
{
    public class EnumToBooleanConverter : IValueConverter
    {
        // **********************************************************************
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value.Equals(parameter);
        }
        // **********************************************************************
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value.Equals(true) ? parameter : Binding.DoNothing;
        }
        // **********************************************************************
    }
}
   using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Data;
    namespace WpfContextMenuWithEnum.Converter
    {
        public class MultiBind2ValueComparerConverter : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (values.Length != 2)
                {
                    throw new ArgumentException("Can compare only 2 values together fo equality");
                }
                return (values[0].Equals(values[1]));
            }
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
            {
                // if ((bool)value == true)
                throw new NotImplementedException();
            }
        }
    }
Trial 1: MultiBindConverter ConvertBack не может работать, он пропускает информацию.
<ContextMenu ItemsSource="{Binding Source={StaticResource EnumChoiceProvider}}">
            <ContextMenu.ItemTemplate>
                <DataTemplate>
                    <MenuItem IsCheckable="True" Header="{Binding Path=.}">
                        <MenuItem.IsChecked>
                            <MultiBinding Converter="{StaticResource MultiBind2ValueComparerConverter}">
                                <Binding Path="DataContext.ModelEnumChoice" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" />
                                <Binding Path="."></Binding>
                            </MultiBinding>
                        </MenuItem.IsChecked>
                    </MenuItem>
                </DataTemplate>
            </ContextMenu.ItemTemplate>
        </ContextMenu>
Судебное разбирательство 2: Связывание с My ConverterParameter не работает вообще. Он никогда не получал никакой ценности
<ContextMenu ItemsSource="{Binding Source={StaticResource EnumChoiceProvider}}">
                    <ContextMenu.ItemTemplate>
                        <DataTemplate>
                            <MenuItem IsCheckable="True" Header="{Binding Path=.}">
                                <MenuItem.IsChecked>
                                    <Binding Path="DataContext.ModelEnumChoice" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}">
                                        <Binding.Converter>
                                            <converter:ConverterWrapperWithDependencyParameterConverter Converter="{StaticResource EnumToBooleanConverter}"
                                                Parameter="{Binding Path=.}"/>
                                        </Binding.Converter>
                                    </Binding>
                                </MenuItem.IsChecked>
                            </MenuItem>
                        </DataTemplate>
                    </ContextMenu.ItemTemplate>
                </ContextMenu>
Испытание 3:
С помощью listBox с использованием шаблона и SelectedItem, но пользовательский интерфейс не является таким стандартным, как он должен быть (появляется дополнительный кадр).

