2010-11-29 116 views
20

我有一个类:WPF数据绑定:如何使用XAML将数据绑定到组合框?

public class AccountDetail 
{ 
    public DetailScope Scope 
    { 
     get { return scope; } 
     set { scope = value; } 
    } 

    public string Value 
    { 
     get { return this.value; } 
     set { this.value = value; } 
    } 

    private DetailScope scope; 
    private string value; 

    public AccountDetail(DetailScope scope, string value) 
    { 
     this.scope = scope; 
     this.value = value; 
    } 
} 

和枚举:

public enum DetailScope 
{ 
    Private, 
    Business, 
    OtherDetail 
} 

最后,我有一个文件名为.xaml:

<Window x:Class="Gui.Wpf.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Test" 
    SizeToContent="WidthAndHeight"> 

    <Grid> 
     <ComboBox 
      Name="ScopeComboBox" 
      Width="120" 
      Height="23" 
      Margin="12" /> 
    </Grid> 
</Window> 

我希望做两件事情:

  1. 我希望数据绑定DetailsScope枚举值组合框值。我不希望 直接绑定枚举值,因为最后一个枚举值将是OtherDetail而不是 Other detail(添加了空格字符和小写字母'd')。
  2. 我希望数据绑定组合框中的选定值到AccountDetail对象的 实例中指定的值。

你能帮我吗?谢谢。

更新:我发现此帖子http://blogs.msdn.com/b/wpfsdk/archive/2007/02/22/displaying-enum-values-using-data-binding.aspx。我需要类似的东西。

回答

37

一个非常简单的方法来做到这一点是使用ObjectDataProvider的

<ObjectDataProvider MethodName="GetValues" 
        ObjectType="{x:Type sys:Enum}" 
        x:Key="DetailScopeDataProvider"> 
    <ObjectDataProvider.MethodParameters> 
     <x:Type TypeName="local:DetailScope" /> 
    </ObjectDataProvider.MethodParameters> 
</ObjectDataProvider> 

使用ObjectDataProvider的作为的ItemsSource组合框,绑定的SelectedItem的作用域属性和应用用于显示每个ComboBoxItem的转换器

<ComboBox Name="ScopeComboBox" 
      ItemsSource="{Binding Source={StaticResource DetailScopeDataProvider}}" 
      SelectedItem="{Binding Scope}" 
      Width="120" 
      Height="23" 
      Margin="12"> 
    <ComboBox.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding Converter={StaticResource CamelCaseConverter}}"/> 
     </DataTemplate> 
    </ComboBox.ItemTemplate> 
</ComboBox> 

而在转换器中,您可以使用Regex for CamelCase string splitter在this问题中找到。我使用了最先进的版本,但您可以使用更简单的版本。 OtherDetail +正则表达式=其他细节。使返回值较低,然后返回一个字符串与第一个字符UpperCase应该给你预期的结果

public class CamelCaseConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     string enumString = value.ToString(); 
     string camelCaseString = Regex.Replace(enumString, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ").ToLower(); 
     return char.ToUpper(camelCaseString[0]) + camelCaseString.Substring(1); 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value; 
    } 
} 
2

这里是一个解决方案:你创建一个包含所有可能性的属性(一个列表),并将你的ComboBox绑定到该属性上。

在XAML:

<ComboBox 
    Name="ScopeComboBox" 
    Width="120" 
    Height="23" 
    Margin="12" 
    ItemsSource="{Binding Path=AccountDetailsProperty}" 
    DisplayMemberPath="Value"/> 

而且在后面的代码:

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     AccountDetailsProperty = new List<AccountDetail>() 
     { 
      new AccountDetail(DetailScope.Business, "Business"), 
      new AccountDetail(DetailScope.OtherDetail, "Other details"), 
      new AccountDetail(DetailScope.Private, "Private"), 
     }; 

     InitializeComponent(); 
     this.DataContext = this; 
    } 

    public List<AccountDetail> AccountDetailsProperty { get; set; } 
} 
+0

尼古拉斯,感谢您的答复。我正在寻找更多面向XAML的解决方案,例如:http://blogs.msdn.com/b/wpfsdk/archive/2007/02/22/displaying-enum-values-using-data-binding.aspx – Boris 2010-11-29 18:49:55

11

的方式我一直做了如下。这个解决方案的优点是它是完全通用的,可以重用于任何枚举类型。

1)当你定义一个枚举时,利用一些自定义属性给出一些信息。在这个例子中,我使用了Browsable(false)来表示这个枚举器是内部的,我不想在组合框中看到这个选项。说明(“”)允许我为枚举指定显示名称。

public enum MyEnumerationTypeEnum 
    { 
    [Browsable(false)] 
    Undefined, 
    [Description("Item 1")] 
    Item1, 
    [Description("Item 2")] 
    Item2, 
    Item3 
    } 

2)定义一个我称之为EnumerationManager的类。这是一个泛型类,用于分析Enumeration类型并生成值列表。如果枚举器将Browsable设置为false,则它将被跳过。如果它有一个Description属性,那么它将使用描述字符串作为显示名称。如果没有找到说明,它只会显示枚举器的默认字符串。

public class EnumerationManager 
    { 
    public static Array GetValues(Type enumeration) 
    { 
     Array wArray = Enum.GetValues(enumeration); 
     ArrayList wFinalArray = new ArrayList(); 
     foreach(Enum wValue in wArray) 
     { 
     FieldInfo fi = enumeration.GetField(wValue.ToString()); 
     if(null != fi) 
     { 
      BrowsableAttribute[] wBrowsableAttributes = fi.GetCustomAttributes(typeof(BrowsableAttribute),true) as BrowsableAttribute[]; 
      if(wBrowsableAttributes.Length > 0) 
      { 
      // If the Browsable attribute is false 
      if(wBrowsableAttributes[0].Browsable == false) 
      { 
       // Do not add the enumeration to the list. 
       continue; 
      }   
      } 

      DescriptionAttribute[] wDescriptions = fi.GetCustomAttributes(typeof(DescriptionAttribute),true) as DescriptionAttribute[]; 
     if(wDescriptions.Length > 0) 
     { 
     wFinalArray.Add(wDescriptions[0].Description); 
     } 
     else 
     wFinalArray.Add(wValue); 
     } 
     } 

     return wFinalArray.ToArray(); 
    } 
    } 

3)在你的XAML在ResourceDictionary中添加部分

<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type l:EnumerationManager}" x:Key="OutputListForMyComboBox"> 
     <ObjectDataProvider.MethodParameters> 
      <x:Type TypeName="l:MyEnumerationTypeEnum" /> 
     </ObjectDataProvider.MethodParameters> 
    </ObjectDataProvider> 

4)现在只需绑定您的组合框的ItemsSource时,我们刚在资源字典定义此键

<ComboBox Name="comboBox2" 
      ItemsSource="{Binding Source={StaticResource OutputListForMyComboBox}}" /> 

如果您使用上面的枚举尝试使用此代码,则应在组合框中看到3个项目:

Item 1 
Item 2 
Item3 

希望这会有所帮助。

EDITS: 如果添加LocalizableDescriptionAttribute的实现并使用它,而不是我使用的Description属性将是完美的。

+0

Liz,谢谢你的回复。 – Boris 2010-11-30 00:47:31

+0

这是一个很好的方法。 – gakera 2015-06-08 16:43:56

+0

将SelectedItem绑定回视图模型的最佳方式是什么?我试图直接绑定到视图模型中的相同类型的枚举,但它然后获取描述作为从控件发送并解析它的字符串(特别是如果本地化)是一种痛苦? – gakera 2015-11-24 13:05:36

0

我会为此使用一个值转换器,这将允许您直接使用转换器进行绑定,您可以更改Convert实现以使enums的“更好”人类可读展示,即分割大写字符。

有一篇关于这种方法的完整文章here

public class MyEnumToStringConverter : IValueConverter 
    { 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value.ToString(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return (MyEnum) Enum.Parse(typeof (MyEnum), value.ToString(), true); 
    } 
    }