我正在尝试使用此答案中的MarkupExtension将WPF ComboBox绑定到枚举值的集合https://stackoverflow.com/a/4398752/964478
它适用于{Binding Source={my:Enumeration {x:Type my:Status}}}
,但我想使用枚举值的集合而不是所有值。
public IList<Status> Statuses
{
get
{
return new[]
{
Status.Available,
Status.Away
};
}
}
我为那个
添加了一个构造函数 public class EnumerationExtension : MarkupExtension
{
private Type _enumType;
private Enum[] _enumValues;
public EnumerationExtension(IEnumerable<Enum> enumValues)
{
_enumValues = enumValues.ToArray();
EnumType = _enumValues.First().GetType();
}
//public EnumerationExtension(Type enumType)
//{
// if (enumType == null)
// throw new ArgumentNullException(nameof(enumType));
// EnumType = enumType;
//}
public Type EnumType
{
get { return _enumType; }
private set
{
if (_enumType == value)
return;
var enumType = Nullable.GetUnderlyingType(value) ?? value;
if (enumType.IsEnum == false)
throw new ArgumentException("Type must be an Enum.");
_enumType = value;
}
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var enumValues = _enumValues ?? Enum.GetValues(EnumType);
return (
from object enumValue in enumValues
select new EnumerationMember
{
Value = enumValue,
Description = GetDescription(enumValue)
}).ToArray();
}
private string GetDescription(object enumValue)
{
var descriptionAttribute = EnumType
.GetField(enumValue.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
return descriptionAttribute != null
? descriptionAttribute.Description
: enumValue.ToString();
}
public class EnumerationMember
{
public string Description { get; set; }
public object Value { get; set; }
}
}
但是当我尝试这样的事情时
ItemsSource="{Binding Source={my:Enumeration Statuses}}"
我在NullReferenceException
InitializeComponent
处获得了 at MS.Internal.Xaml.Runtime.ClrObjectRuntime.GetConverterInstance[TConverterBase](XamlValueConverter`1 converter)
at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CreateObjectWithTypeConverter(ServiceProviderContext serviceContext, XamlValueConverter`1 ts, Object value)
at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CreateFromValue(ServiceProviderContext serviceContext, XamlValueConverter`1 ts, Object value, XamlMember property)
at MS.Internal.Xaml.Runtime.PartialTrustTolerantRuntime.CreateFromValue(ServiceProviderContext serviceContext, XamlValueConverter`1 ts, Object value, XamlMember property)
at System.Xaml.XamlObjectWriter.Logic_CreateFromValue(ObjectWriterContext ctx, XamlValueConverter`1 typeConverter, Object value, XamlMember property, String targetName, IAddLineInfo lineInfo)
at System.Xaml.XamlObjectWriter.Logic_ConvertPositionalParamsToArgs(ObjectWriterContext ctx)
at System.Xaml.XamlObjectWriter.WriteEndMember()
at System.Xaml.XamlWriter.WriteNode(XamlReader reader)
at System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader, XamlObjectWriter xamlWriter, Boolean onlyLoadOneNode, Boolean skipJournaledProperties, Boolean shouldPassLineNumberInfo, IXamlLineInfo xamlLineInfo, IXamlLineInfoConsumer xamlLineInfoConsumer, XamlContextStack`1 stack, IStyleConnector styleConnector)
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at MvvmLight3.MainWindow.InitializeComponent() in \MainWindow.xaml:line 1
at MvvmLight3.MainWindow..ctor() in \MainWindow.xaml.cs:line 16
{{1}}
答案 0 :(得分:1)
ItemsSource="{Binding Source={my:Enumeration Statuses}}"
不在此处:
my:Enumeration
Enumeration
不是绑定。应该为ProvideValue
的构造函数提供什么值?你无法在那里放置绑定:请注意,在加载XAML时会抛出异常。你的viewmodel还没有出现一段时间。我猜你可以在Binding
中以编程方式创建一个绑定,但是......这会增加什么?您已经有一个标记扩展来创建绑定:它被称为MarkupExtension
。
在这种情况下,我实际上甚至不理解为什么你需要ItemsSource="{Binding Statuses}"
:你不需要它来枚举任何东西,因为你处理它的是一个枚举。
我可能会遗漏一些东西,但这不会做你想要的吗?
MarkupExtension
enum枚举Enum.GetValues(typeof(MyEnumType)).Cast<MyEnumType>();
的优点是你只需给它一个类型,它可以省去你自己创建列表的麻烦,或者为返回{{1}}的属性编写代码。但是你已经自己制作了这份清单。
答案 1 :(得分:1)
您可以创建一个获取枚举值并返回其描述的转换器,而不是使用MarkupExtension。然后在绑定时使用此转换器。
public class EnumToDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return String.Empty;
}
Type type = value.GetType();
return
type.IsEnum
? GetDescription(type, value)
: String.Empty;
}
private string GetDescription(Type enumType, object enumValue)
{
var descriptionAttribute =
enumType
.GetField(enumValue.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
return
descriptionAttribute != null
? descriptionAttribute.Description
: enumValue.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
构建项目后,当您的命名空间作为xml命名空间添加时,您可以在XAML中使用它:
<Window [...] xmlns:local="clr-namespace:YourNameSpace">
将此转换器添加到窗口(或应用程序)资源:
<Window.Resources>
<local:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter" />
</Window.Resources>
然后,您可以在将Statuses
绑定到ListBox时使用它。
<ListBox ItemsSource="{Binding Statuses}" SelectedItem="{Binding CurrentStatus}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumToDescriptionConverter}}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
CurrentStatus
和Statuses
是viewmodel的属性:
public class MainViewModel
{
public Status CurrentStatus { get; set; }
public IEnumerable<Status> Statuses
{
get
{
return new Status[]
{
Status.Available,
Status.Away
};
}
}
}