WPF Data binding: comment lier des données avec XAML? [dupliquer]

cette question a déjà une réponse ici:

j'ai une classe:

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

et un enum:

public enum DetailScope
{
    Private, 
    Business, 
    OtherDetail
}

enfin, j'ai un .fichier 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>

je voudrais faire deux choses:

  1. je souhaite lier les données DetailsScope aux valeurs de la boîte bascule. Je ne souhaite pas liez les valeurs enum directement parce que la dernière valeur enum serait OtherDetail au lieu de Other detail (ajout d'un caractère d'espace et d'une petite lettre "d").
  2. je souhaite que les données lient la valeur sélectionnée dans la boîte bascule à celle spécifiée dans le instance du AccountDetail objet.

Pourriez-vous m'aider? Grâce.

mise à jour: j'ai trouvé ce post http://blogs.msdn.com/b/wpfsdk/archive/2007/02/22/displaying-enum-values-using-data-binding.aspx . J'ai besoin de quelque chose de similaire.

20
demandé sur Fredrik Hedblad 2010-11-29 21:21:25

4 réponses

une façon assez facile de faire cela est d'utiliser un ObjectDataProvider

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

utiliser ObjectDataProvider comme source Itemss pour le ComboBox, lier SelectedItem à la propriété Scope et appliquer un convertisseur pour l'affichage de chaque 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>

et dans le convertisseur vous pouvez utiliser Regex pour le séparateur de corde de CamelCase trouvé dans cette" question 151990920". J'ai utilisé la version la plus avancée, mais vous pouvez probablement utiliser un plus simple. OtherDetail + la regex = Autres Détails. Faire en sorte que la valeur de retour soit plus basse et ensuite retourner une chaîne avec le premier caractère en majuscules devrait vous donner le résultat attendu

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]))", " ").ToLower();
        return char.ToUpper(camelCaseString[0]) + camelCaseString.Substring(1);
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }
}
37
répondu Fredrik Hedblad 2017-05-23 12:09:39

la façon dont je l'ai toujours fait est la suivante. La beauté de cette solution est qu'elle est complètement générique, et peut être réutilisée pour tous les types d'énumération.

1) Lorsque vous définissez une énumération faites usage de certains attributs personnalisés pour donner un peu d'information. Dans cet exemple, j'ai utilisé Consultable(faux) pour indiquer que cette énumérateur est interne, et je ne veux pas voir cette option dans une liste déroulante. Description("") me permet de spécifier un nom d'Affichage pour le énumération.

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

2) Définir une classe que j'ai appelé Énumerationmanager. C'est une classe générique qui analyse un type d'Énumération et génère une liste de valeurs. Si un recenseur a Browsable défini à false il sera sauté. S'il a un attribut Description, alors il utilisera la chaîne de description comme nom d'affichage. Si aucune description n'est trouvée, il affichera simplement la chaîne par défaut de l'énumérateur.

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) dans votre XAML ajouter une section dans votre "ResourceDictionary

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

4) liez maintenant la source Itemss de votre combobox à cette clé que nous venons de définir dans le dictionnaire de ressources

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

si vous essayez ce code en utilisant mon énumération ci-dessus, vous devriez voir 3 articles dans votre boîte de combo:

Item 1
Item 2
Item3

Espérons que cette aide.

: Si vous ajoutez la mise en œuvre du LocalizableDescriptionAttribute et utilisez à la place l'attribut Description que j'utilisais qui serait parfait.

11
répondu Liz 2010-11-29 20:49:45

Voici une solution : vous créez une propriété (une liste) qui contient toutes les possibilités et vous liez votre ComboBox sur cette propriété.

dans le XAML:

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

et dans le code derrière:

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; }
}
2
répondu Nicolas 2010-11-29 18:39:30

je voudrais utiliser un convertisseur de valeur pour cela, cela vous permettra de lier directement en utilisant le convertisseur, vous pouvez changer l'implémentation de convertir pour faire une présentation plus" agréable " lisible par l'homme des enums, c.-à-d. divisé sur les caractères capitalisés.

il y a un article complet sur cette approche ici .

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

0
répondu BrokenGlass 2010-11-29 19:21:32