C# 从枚举值列表创建可检查上下文菜单的通用方法

C# 从枚举值列表创建可检查上下文菜单的通用方法,c#,wpf,xaml,enums,menuitem,C#,Wpf,Xaml,Enums,Menuitem,我想创建一个上下文菜单,其中一个菜单项是一个子菜单,可以在枚举值中进行选择 我不想将枚举中的任何值硬编码到xaml中,因为我希望任何枚举值更改都能自动反映在UI中,而无需任何干预 我希望我的菜单是一个没有任何工件的常规上下文菜单(我的意思是外观应该是一个常规上下文菜单) 我尝试了很多方法,但都没有成功。我的每一次尝试都会遗漏一些东西,但主要是缺少的部分似乎是可能绑定到某个东西的转换器参数 我是红色的: 这是我的许多试验和相关代码: <Window x:Class="WpfCont

我想创建一个上下文菜单,其中一个菜单项是一个子菜单,可以在枚举值中进行选择

我不想将枚举中的任何值硬编码到xaml中,因为我希望任何枚举值更改都能自动反映在UI中,而无需任何干预

我希望我的菜单是一个没有任何工件的常规上下文菜单(我的意思是外观应该是一个常规上下文菜单)

我尝试了很多方法,但都没有成功。我的每一次尝试都会遗漏一些东西,但主要是缺少的部分似乎是可能绑定到某个东西的转换器参数

我是红色的:

这是我的许多试验和相关代码:

<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>
试用版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:我的转换器参数绑定根本不起作用。它从未得到任何价值

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


使用template和SelectedItem创建列表框,但UI并不像应有的那样标准(会出现一个额外的框架)。

因此您希望能够

  • 将任何
    Enum
    绑定到
    ContextMenu
    并显示其
    Description
    属性
  • 在所选的
    枚举
    前面有一个复选标记,在任何给定时间只有一个可以“激活”
  • 将所选值存储在ViewModel中,并在选择更改时执行某些逻辑
像下面这样的


main window.xaml

<Window x:Class="WpfApplication1.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModel="clr-namespace:WpfApplication1.ViewModel"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow"
        Height="300"
        Width="250">

    <!-- Set data context -->        
    <Window.DataContext>
      <viewModel:MainViewModel />
    </Window.DataContext>

    <!-- Converters -->
    <Window.Resources>
      <local:EnumDescriptionConverter x:Key="EnumDescriptionConverter" />
      <local:EnumCheckedConverter x:Key="EnumCheckedConverter" />
    </Window.Resources>

    <!-- Element -->    
    <TextBox Text="Right click me">
      <!-- Context menu -->
      <TextBox.ContextMenu>
        <ContextMenu ItemsSource="{Binding EnumChoiceProvider}">
          <ContextMenu.ItemTemplate>
            <DataTemplate>
              <!-- Menu item header bound to enum converter -->
              <!-- IsChecked bound to current selection -->
              <!-- Toggle bound to a command, setting current selection -->
              <MenuItem 
                IsCheckable="True"
                Width="150"
                Header="{Binding Path=., Converter={StaticResource EnumDescriptionConverter}}"
                Command="{Binding DataContext.ToggleEnumChoiceCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
                CommandParameter="{Binding}">
                <MenuItem.IsChecked>
                  <MultiBinding Mode="OneWay" 
                                NotifyOnSourceUpdated="True" 
                                UpdateSourceTrigger="PropertyChanged" 
                                Converter="{StaticResource EnumCheckedConverter}">
                    <Binding Path="DataContext.SelectedEnumChoice" 
                             RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}"  />
                    <Binding Path="."></Binding>
                  </MultiBinding>
                </MenuItem.IsChecked>    
              </MenuItem>
            </DataTemplate>
          </ContextMenu.ItemTemplate>
        </ContextMenu>
      </TextBox.ContextMenu>
    </TextBox>
</Window>
EnumCheckedConverter.cs

namespace WpfApplication1.ViewModel
{
    public class MainViewModel : ViewModelBase // where base implements INotifyPropertyChanged
    {
        private EnumChoice? _selectedEnumChoice;

        public MainViewModel()
        {
            EnumChoiceProvider = new ObservableCollection<EnumChoice>
                (Enum.GetValues(typeof(EnumChoice)).Cast<EnumChoice>());

            ToggleEnumChoiceCommand = new RelayCommand<EnumChoice>
                (arg => SelectedEnumChoice = arg);
        }

        // Selections    
        public ObservableCollection<EnumChoice> EnumChoiceProvider { get; set; }

        // Current selection    
        public EnumChoice? SelectedEnumChoice
        {
            get
            {
                return _selectedEnumChoice;
            }
            set
            {
                _selectedEnumChoice = value != _selectedEnumChoice ? value : null;
                RaisePropertyChanged();
            }
        }

        // "Selection changed" command    
        public ICommand ToggleEnumChoiceCommand { get; private set; }
    }
}
namespace WpfApplication1
{
    public enum EnumChoice
    {
        [Description("Default")]
        ChoiceDefault,
        [Description("<1>")]
        Choice1,
        [Description("<2>")]
        Choice2
    }
}
namespace WpfApplication1
{
    // Extract enum description 
    public class EnumDescriptionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            MemberInfo[] memberInfos = value.GetType().GetMember(value.ToString());

            if (memberInfos.Length > 0)
            {
                object[] attrs = memberInfos[0].GetCustomAttributes(typeof (DescriptionAttribute), false);
                if (attrs.Length > 0)
                    return ((DescriptionAttribute) attrs[0]).Description;
            }

            return value;

            // or maybe just
            //throw new InvalidEnumArgumentException(string.Format("no description found for enum {0}", value));
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
namespace WpfApplication1
{
    // Check if currently selected 
    public class EnumCheckedConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            return !values.Contains(null) && values[0].ToString().Equals(values[1].ToString(), StringComparison.OrdinalIgnoreCase);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

我添加我的解决方案作为参考。两种解决方案(已接受的答案和我的答案都很好)。我在等待一个有效的完整答案的同时创建了一个。我认为Mikko有一种更标准的工作方式,并且可能更容易维护。Mikko解决方案还展示了一些WPF技巧(Relaycommand、MultiBinding等)的良好用法

我的解决方案的主要优点是通过使用通用代码来抽象“复杂性”,该代码模拟表示每个枚举值及其属性(IsChecked、Name、DisplayName)的项集合。所有这些都是隐藏的,不需要模型中的任何内容。 但不管怎样,就像其他信息一样

<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"
        Title="MainWindow" Height="350" Width="525"
        Name="MyWindow">
    <Window.DataContext>
        <wpfContextMenuWithEnum:MainWindowModel></wpfContextMenuWithEnum:MainWindowModel>
    </Window.DataContext>

    <Window.Resources>
        <wpfContextMenuWithEnum:EnumWrapperIteratorAndSelector x:Key="EnumWrapperIteratorAndSelector" 
                                                               Enum="{Binding DataContext.SelectedEnumChoice, Mode=TwoWay, ElementName=MyWindow}" />
    </Window.Resources>

    <Grid>
        <TextBox Text="Right click me">
            <TextBox.ContextMenu>
                <ContextMenu ItemsSource="{Binding Source={StaticResource EnumWrapperIteratorAndSelector}}">
                    <ContextMenu.ItemTemplate>
                        <DataTemplate>
                            <MenuItem IsCheckable="True" Header="{Binding DisplayName}" IsChecked="{Binding IsChecked}">
                            </MenuItem>
                        </DataTemplate>
                    </ContextMenu.ItemTemplate>
                </ContextMenu>
            </TextBox.ContextMenu>
        </TextBox>
    </Grid>
</Window>

可以在任何地方使用的泛型类:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Reflection;
    using System.Windows;

    namespace WpfContextMenuWithEnum
    {
        /// <summary>
        /// Note: Freezable is necessary otherwise binding will never occurs if EnumWrapperIteratorAndSelector is defined
        /// as resources. See article for more info: 
        /// http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
        ///  </summary>
        public class EnumWrapperIteratorAndSelector : Freezable, IEnumerable<EnumWrapperIteratorAndSelectorChoice>, INotifyCollectionChanged
        {
            // ******************************************************************
            public static readonly DependencyProperty EnumProperty =
                DependencyProperty.Register("Enum", typeof(Enum), typeof(EnumWrapperIteratorAndSelector), new PropertyMetadata(null, PropertyChangedCallback));

            ObservableCollection<EnumWrapperIteratorAndSelectorChoice> _allEnumValue = new ObservableCollection<EnumWrapperIteratorAndSelectorChoice>();

            // ******************************************************************
            private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (!(dependencyPropertyChangedEventArgs.NewValue is Enum))
                {
                    throw new ArgumentException("Only enum are supported.");
                }

                var me = dependencyObject as EnumWrapperIteratorAndSelector;
                if (me != null)
                {
                    if (dependencyPropertyChangedEventArgs.OldValue == null)
                    {
                        me.ResetWithNewEnum(dependencyPropertyChangedEventArgs.NewValue);
                    }
                    else
                    {
                        foreach(EnumWrapperIteratorAndSelectorChoice enumWrapperIteratorAndSelectorChoice in me._allEnumValue)
                        {
                            enumWrapperIteratorAndSelectorChoice.RaiseChangeIfAppropriate(dependencyPropertyChangedEventArgs);
                        }
                    }
                }
            }

            // ******************************************************************
            private void ResetWithNewEnum(object enumValue)
            {
                _allEnumValue.Clear();

                var enumType = Enum.GetType();
                foreach (Enum enumValueIter in Enum.GetValues(enumValue.GetType()))
                {
                    MemberInfo[] memberInfos = enumType.GetMember(enumValueIter.ToString());
                    if (memberInfos.Length > 0)
                    {
                        var desc = memberInfos[0].GetCustomAttribute<DescriptionAttribute>();
                        if (desc != null)
                        {
                            _allEnumValue.Add(new EnumWrapperIteratorAndSelectorChoice(this, enumValueIter, desc.Description));
                        }
                        else
                        {
                            _allEnumValue.Add(new EnumWrapperIteratorAndSelectorChoice(this, enumValueIter));
                        }
                    }
                }
            }

            // ******************************************************************
            public Enum Enum
            {
                get { return (Enum)GetValue(EnumProperty); }
                set
                {
                    SetValue(EnumProperty, value);
                }
            }

            // ******************************************************************
            internal void SetCurrentValue(Enum enumValue)
            {
                SetCurrentValue(EnumProperty, enumValue);
            }

            // ******************************************************************
            public IEnumerator GetEnumerator()
            {
                return _allEnumValue.GetEnumerator();
            }

            // ******************************************************************
            IEnumerator<EnumWrapperIteratorAndSelectorChoice> IEnumerable<EnumWrapperIteratorAndSelectorChoice>.GetEnumerator()
            {
                return _allEnumValue.GetEnumerator();
            }

            // ******************************************************************
            public event NotifyCollectionChangedEventHandler CollectionChanged
            {
                add { _allEnumValue.CollectionChanged += value; }
                remove { _allEnumValue.CollectionChanged -= value; }
            }

            // ******************************************************************
            protected override Freezable CreateInstanceCore()
            {
                return new EnumWrapperIteratorAndSelector();
            }

            // ******************************************************************

        }
    }

    using System;
    using System.ComponentModel;
    using System.Windows;

    namespace WpfContextMenuWithEnum
    {
        public class EnumWrapperIteratorAndSelectorChoice : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;

            private EnumWrapperIteratorAndSelector _enumWrapperIteratorAndSelector;
            public Enum EnumValueRef { get; private set; }
            public string Name { get; set; }
            public string Description { get; set; }

            public bool IsChecked
            {
                get
                {
                    return _enumWrapperIteratorAndSelector.Enum.Equals(EnumValueRef);
                }

                set
                {
                    if (value) // Can only set value
                    {
                        _enumWrapperIteratorAndSelector.SetCurrentValue(EnumValueRef);
                    }
                }
            }

            internal void RaiseChangeIfAppropriate(DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (EnumValueRef.Equals(dependencyPropertyChangedEventArgs.OldValue) ||
                    EnumValueRef.Equals(dependencyPropertyChangedEventArgs.NewValue))
                {
                    var propertyChangeLocal = PropertyChanged;
                    if (propertyChangeLocal != null)
                    {
                        propertyChangeLocal(this, new PropertyChangedEventArgs("IsChecked"));
                    }
                }
            }

            public EnumWrapperIteratorAndSelectorChoice(EnumWrapperIteratorAndSelector enumWrapperIteratorAndSelector,
                Enum enumValueRef, string description = null)
            {
                _enumWrapperIteratorAndSelector = enumWrapperIteratorAndSelector;
                EnumValueRef = enumValueRef;
                Name = enumValueRef.ToString();
                Description = description;
            }

            public string DisplayName
            {
                get { return Description ?? Name; }
            }
        }
    }

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;

namespace WpfContextMenuWithEnum
{
    public class MainWindowModel : ViewModelBase
    {
        private EnumChoice _selectedEnumChoice;

        public EnumChoice SelectedEnumChoice
        {
            get { return _selectedEnumChoice; }
            set { _selectedEnumChoice = value; RaisePropertyChanged(); }
        }
    }
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.Collections.Specialized;
使用系统组件模型;
运用系统反思;
使用System.Windows;
命名空间WpfContextMenuWithEnum
{
/// 
///注意:如果定义了EnumWrapperIteratorAndSelector,则Freezable是必需的,否则将永远不会发生绑定
///作为参考资料。有关更多信息,请参阅文章:
/// http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
///  
公共类EnumWrapperIteratorAndSelector:Freezable、IEnumerable、INotifyCollectionChanged
{
// ******************************************************************
公共静态只读DependencyProperty EnumProperty=
Register(“Enum”、typeof(Enum)、typeof(EnumWrapperIteratorAndSelector)、newPropertyMetadata(null、PropertyChangedCallback));
ObservableCollection_allEnumValue=新的ObservableCollection();
// ******************************************************************
私有静态无效属性ChangedCallback(DependencyObject DependencyObject,DependencyPropertyChangedEventArgs DependencyPropertyChangedEventArgs)
{
如果(!(dependencyPropertyChangedEventArgs.NewValue为枚举))
{
抛出新ArgumentException(“仅支持枚举”);
}
var me=作为EnumWrapperIterator和Selector的dependencyObject;
如果(me!=null)
{
if(dependencPropertyChangedEventArgs.OldValue==null)
{
me.ResetWithNewEnum(dependencPropertyChangedEventArgs.NewValue);
}
其他的
{
foreach(EnumWrapperIterator和SelectorChoice EnumWrapperIterator和SelectorChoice in me.\u allEnumValue)
{
EnumWrapperIterator和SelectorChoice.RaiseChangeIf适当(dependencyPropertyChangedEventArgs);
}
}
}
}
// ******************************************************************
私有void ResetWithNewEnum(对象枚举值)
{
_allEnumValue.Clear();
var enumType=Enum.GetType();
foreach(枚举)
<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"
        Title="MainWindow" Height="350" Width="525"
        Name="MyWindow">
    <Window.DataContext>
        <wpfContextMenuWithEnum:MainWindowModel></wpfContextMenuWithEnum:MainWindowModel>
    </Window.DataContext>

    <Window.Resources>
        <wpfContextMenuWithEnum:EnumWrapperIteratorAndSelector x:Key="EnumWrapperIteratorAndSelector" 
                                                               Enum="{Binding DataContext.SelectedEnumChoice, Mode=TwoWay, ElementName=MyWindow}" />
    </Window.Resources>

    <Grid>
        <TextBox Text="Right click me">
            <TextBox.ContextMenu>
                <ContextMenu ItemsSource="{Binding Source={StaticResource EnumWrapperIteratorAndSelector}}">
                    <ContextMenu.ItemTemplate>
                        <DataTemplate>
                            <MenuItem IsCheckable="True" Header="{Binding DisplayName}" IsChecked="{Binding IsChecked}">
                            </MenuItem>
                        </DataTemplate>
                    </ContextMenu.ItemTemplate>
                </ContextMenu>
            </TextBox.ContextMenu>
        </TextBox>
    </Grid>
</Window>
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Reflection;
    using System.Windows;

    namespace WpfContextMenuWithEnum
    {
        /// <summary>
        /// Note: Freezable is necessary otherwise binding will never occurs if EnumWrapperIteratorAndSelector is defined
        /// as resources. See article for more info: 
        /// http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
        ///  </summary>
        public class EnumWrapperIteratorAndSelector : Freezable, IEnumerable<EnumWrapperIteratorAndSelectorChoice>, INotifyCollectionChanged
        {
            // ******************************************************************
            public static readonly DependencyProperty EnumProperty =
                DependencyProperty.Register("Enum", typeof(Enum), typeof(EnumWrapperIteratorAndSelector), new PropertyMetadata(null, PropertyChangedCallback));

            ObservableCollection<EnumWrapperIteratorAndSelectorChoice> _allEnumValue = new ObservableCollection<EnumWrapperIteratorAndSelectorChoice>();

            // ******************************************************************
            private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (!(dependencyPropertyChangedEventArgs.NewValue is Enum))
                {
                    throw new ArgumentException("Only enum are supported.");
                }

                var me = dependencyObject as EnumWrapperIteratorAndSelector;
                if (me != null)
                {
                    if (dependencyPropertyChangedEventArgs.OldValue == null)
                    {
                        me.ResetWithNewEnum(dependencyPropertyChangedEventArgs.NewValue);
                    }
                    else
                    {
                        foreach(EnumWrapperIteratorAndSelectorChoice enumWrapperIteratorAndSelectorChoice in me._allEnumValue)
                        {
                            enumWrapperIteratorAndSelectorChoice.RaiseChangeIfAppropriate(dependencyPropertyChangedEventArgs);
                        }
                    }
                }
            }

            // ******************************************************************
            private void ResetWithNewEnum(object enumValue)
            {
                _allEnumValue.Clear();

                var enumType = Enum.GetType();
                foreach (Enum enumValueIter in Enum.GetValues(enumValue.GetType()))
                {
                    MemberInfo[] memberInfos = enumType.GetMember(enumValueIter.ToString());
                    if (memberInfos.Length > 0)
                    {
                        var desc = memberInfos[0].GetCustomAttribute<DescriptionAttribute>();
                        if (desc != null)
                        {
                            _allEnumValue.Add(new EnumWrapperIteratorAndSelectorChoice(this, enumValueIter, desc.Description));
                        }
                        else
                        {
                            _allEnumValue.Add(new EnumWrapperIteratorAndSelectorChoice(this, enumValueIter));
                        }
                    }
                }
            }

            // ******************************************************************
            public Enum Enum
            {
                get { return (Enum)GetValue(EnumProperty); }
                set
                {
                    SetValue(EnumProperty, value);
                }
            }

            // ******************************************************************
            internal void SetCurrentValue(Enum enumValue)
            {
                SetCurrentValue(EnumProperty, enumValue);
            }

            // ******************************************************************
            public IEnumerator GetEnumerator()
            {
                return _allEnumValue.GetEnumerator();
            }

            // ******************************************************************
            IEnumerator<EnumWrapperIteratorAndSelectorChoice> IEnumerable<EnumWrapperIteratorAndSelectorChoice>.GetEnumerator()
            {
                return _allEnumValue.GetEnumerator();
            }

            // ******************************************************************
            public event NotifyCollectionChangedEventHandler CollectionChanged
            {
                add { _allEnumValue.CollectionChanged += value; }
                remove { _allEnumValue.CollectionChanged -= value; }
            }

            // ******************************************************************
            protected override Freezable CreateInstanceCore()
            {
                return new EnumWrapperIteratorAndSelector();
            }

            // ******************************************************************

        }
    }

    using System;
    using System.ComponentModel;
    using System.Windows;

    namespace WpfContextMenuWithEnum
    {
        public class EnumWrapperIteratorAndSelectorChoice : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;

            private EnumWrapperIteratorAndSelector _enumWrapperIteratorAndSelector;
            public Enum EnumValueRef { get; private set; }
            public string Name { get; set; }
            public string Description { get; set; }

            public bool IsChecked
            {
                get
                {
                    return _enumWrapperIteratorAndSelector.Enum.Equals(EnumValueRef);
                }

                set
                {
                    if (value) // Can only set value
                    {
                        _enumWrapperIteratorAndSelector.SetCurrentValue(EnumValueRef);
                    }
                }
            }

            internal void RaiseChangeIfAppropriate(DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                if (EnumValueRef.Equals(dependencyPropertyChangedEventArgs.OldValue) ||
                    EnumValueRef.Equals(dependencyPropertyChangedEventArgs.NewValue))
                {
                    var propertyChangeLocal = PropertyChanged;
                    if (propertyChangeLocal != null)
                    {
                        propertyChangeLocal(this, new PropertyChangedEventArgs("IsChecked"));
                    }
                }
            }

            public EnumWrapperIteratorAndSelectorChoice(EnumWrapperIteratorAndSelector enumWrapperIteratorAndSelector,
                Enum enumValueRef, string description = null)
            {
                _enumWrapperIteratorAndSelector = enumWrapperIteratorAndSelector;
                EnumValueRef = enumValueRef;
                Name = enumValueRef.ToString();
                Description = description;
            }

            public string DisplayName
            {
                get { return Description ?? Name; }
            }
        }
    }

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;

namespace WpfContextMenuWithEnum
{
    public class MainWindowModel : ViewModelBase
    {
        private EnumChoice _selectedEnumChoice;

        public EnumChoice SelectedEnumChoice
        {
            get { return _selectedEnumChoice; }
            set { _selectedEnumChoice = value; RaisePropertyChanged(); }
        }
    }
}