有没有更好的方法在控件中显示枚举,例如组合框

Is there a better way to show enums in a control, eg combobox

我的目标是以用户友好的字符串格式而不是代码值向用户展示可用枚举的列表,并在需要时显示 属性。 鉴于 DataAnnotations 命名空间在 8.1 通用应用程序中不存在,我不能简单地应用 [Display(Name="Nice display string")]

我改为使用 IValueConverter 到 运行 传入枚举的 switch 语句和 return 我想要的字符串,反之亦然,如果无法转换。 在视图模型中,我 returning a List<Enum> 作为可绑定数据源(对于组合框),为此所选项目绑定到视图模型中的相对 属性。

测试时,这有效 - 字符串以用户友好的格式显示,属性 正在更改并正确设置枚举值。然而,Visual Studio 设计器(随机)抛出一个 xaml 解析异常(我很确定这是由于 combobox.itemtemplate 上的绑定标记而抛出的),这从来都不是理想的。

所以,我的问题 - 有没有更好的方法来实现我的目标而不抛出异常?即使应用程序编译并且 运行s,xaml 错误是否值得关注?

我的转换器

public class FactToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        Fact input = (Fact)value;
        switch (input)
        {
            case Fact.Wrong:
                return "Your Fact is Incorect";
            case Fact.Right:
                return "Your Fact is Correct";
            default:
                throw new ArgumentOutOfRangeException("value", "Fact to string conversion failed as selected enum value has no corresponding string output set up.");
        }
    }
}

我的可绑定物品来源

public List<Fact> FactList
{
    get
    {
        return new List<Fact>
        {
            Fact.Wrong,
            Fact.Right,
        };
    }
}

和我的xaml

<ComboBox Header="Sample Fact:" Margin="0,10" ItemsSource="{Binding FactList}"
          SelectedItem="{Binding CurrentFact, Mode=TwoWay}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Grid DataContext="{Binding}">
                <TextBlock Text="{Binding Converter={StaticResource FactConv}}"/>
            </Grid>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

仅仅因为缺少 DisplayAnnotations 命名空间,并不意味着您不能使用 Display。只需创建您自己的属性 class。 Please see this answer to another question for how to do that.

VS 的设计者确实会无缘无故地随机抛出一些异常,所以这并不是那么重要。现在,如果在运行时抛出异常 - 这是一个严重的问题,您需要解决它!

旁注:DataTemplate 中的 Grid 不需要 DataContext={Binding}

显示属性实现

[System.AttributeUsage(System.AttributeTargets.All)]
public class Display : System.Attribute
{
    private string _name;
    public Display(string name)
    { _name = name; }
    public string GetName()
    { return _name; }
}

转换器

public class EnumWithDisplayConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        try
        {
            string output = value.GetType()
                .GetTypeInfo()
                .GetDeclaredField(((Enum)value).ToString())
                .GetCustomAttribute<Display>()
                .GetName();
            return output;
        }
        catch (NullReferenceException)
        {
            return ((Enum)value).ToString();
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}