WPF Data binding: How to data bind an enum to combo box using XAML? [duplicate]

懵懂的女人 提交于 2019-12-17 22:15:08

问题


I have a class:

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;
    }
}

and an enum:

public enum DetailScope
{
    Private, 
    Business, 
    OtherDetail
}

Lastly, I have a .xaml file:

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

I would like to do two things:

  1. I wish to data bind DetailsScope enum values to the combo box values. I don't wish to bind enum values directly because the last enum value would be OtherDetail instead of Other detail (added a space character and small letter 'd').
  2. I wish to data bind the selected value in the combo box to the one specified in the instance of the AccountDetail object.

Could you help me out? Thanks.

Update: I found this post http://blogs.msdn.com/b/wpfsdk/archive/2007/02/22/displaying-enum-values-using-data-binding.aspx. I need something similar.


回答1:


A pretty easy way to do this is to use an ObjectDataProvider

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

Use the ObjectDataProvider as the ItemsSource for the ComboBox, bind SelectedItem to the Scope property and apply a converter for the display of each 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>

And in the converter you can use Regex for CamelCase string splitter found in this question. I used the most advanced version but you can probably use a simplier one. OtherDetail + the regex = Other Detail. Making return value lower and then return a string with first Character UpperCase should give you expected result

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:


The way I have always done it is as follows. The beauty of this solution is that it is completely generic, and can be re-used for any enumeration types.

1) When you define an enumeration make use of some custom attributes to give a little information. In this example I've used Browsable(false) to indicate that this enumerator is internal, and I don't want to see this option in a combo box. Description("") allows me to specify a Display name for the enumeration.

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

2) Define a class which I've called EnumerationManager. This is a generic class that analyzes an Enumeration type and generates a list of values. If an enumerator has Browsable set to false it will be skipped. If it has a Description attribute then it will use the description string as the display name. If no description is found it will just show the default string of the enumerator.

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) In your xaml add a section in your ResourceDictionary

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

4) Now just bind the ItemsSource of your combobox to this key we just defined in the resource dictionary

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

If you try this code using my enumeration above you should see 3 items in your combo box:

Item 1
Item 2
Item3

Hope this helps.

EDITS: If you add the implementation of the LocalizableDescriptionAttribute and use that instead the Description attribute that I was using that would be perfect.




回答3:


Here is a solution : you create a property (a list) which contains all the possibilities and you bind your ComboBox on that property.

In the XAML :

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

And in the code behind :

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; }
}



回答4:


I would use a Value Converter for this, this will allow you to bind directly using the converter, you can change the Convert implementation to make for a "nicer" human readable presentation of the enums, i.e. split on capitalized characters.

There's a full article about this approach 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 );
     }
  }



来源:https://stackoverflow.com/questions/4306743/wpf-data-binding-how-to-data-bind-an-enum-to-combo-box-using-xaml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!