Problemas com vinculação de enum para ComboBox WPF

2 respostas
K

Olá gente.

Estou com um problema aqui que já me bati para resolver e não consegui ainda.

Estou aprendendo WPF, e estou tentando vincular um Enum a um ComboBox já tentei de diversas maneiras e nada, Com o código que consegui fazer sem erros eu consegui apenas alterar e até gravar a informação mas não consigo exibir novamente a informação ao carregar.

Alguém pode me ajudar por favor.

Segue os códigos da solução.

O enum que quero vincular.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;

namespace Business.Enum
{
    public enum ConfNomesBancoDados
    {
        [DescriptionAttribute("PostgreSQL 8.5")]
        PostgreSQl,
        [DescriptionAttribute("Firebird 2.5")]
        Firebird,
        [DescriptionAttribute("MySql 3.0")]
        MySql
    }
}
O Dicionário base e também com a implementação de um converter (Mas to pensando em separar o converter para aumentar a legibilidade.)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections;
using System.Windows.Data;

namespace ClienteWPF
{
    public class DicionaryEnumBase : Dictionary<String,Object>,IValueConverter
    {
        public DicionaryEnumBase()
        {
        }

        private Type EnumType { get; set; }

        public void Load(Type EnumType)
        {
            this.EnumType = EnumType;
            Array enumValues = Enum.GetValues(EnumType);
            foreach(Object t in enumValues){
                Add( GetDescription(t,EnumType), t);
            }
        }
        
        private string GetDescription(object enumValue, Type enumType)
        {
            var descriptionAttribute = enumType
              .GetField(enumValue.ToString())
              .GetCustomAttributes(typeof(DescriptionAttribute), false)
              .FirstOrDefault() as DescriptionAttribute;


            return descriptionAttribute != null
              ? descriptionAttribute.Description
              : enumValue.ToString();
        }

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            String key = GetDescription(value,EnumType);
            return key;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try
            {
                KeyValuePair<String, Object> o = (KeyValuePair<String, Object>)value;
                foreach (Object en in Enum.GetValues(EnumType))
                {
                    String key = o.Key;
                    if (GetDescription(en, EnumType).Equals(key))
                    {
                        return en;
                    }
                }
            }
            catch (Exception ex)
            {
                return value;
            }
            
            
            return value;
        }
    }
}

O XAML que define a apresentação.

<Page x:Class="ClienteWPF.ConfiguracaoView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d"
      xmlns:en="clr-namespace:Business.Enum;assembly=Business"
      xmlns:dic="clr-namespace:ClienteWPF.Dicionary"
      Title="ConfiguracaoView" Loaded="Page_Loaded_1" Width="796.24" Height="500
      ">
    <Page.Resources>
        <dic:ConfNomesBancoDadosDic x:Key="nomesDb"/>
    </Page.Resources>
    <Grid>
        <TabControl HorizontalAlignment="Left" Height="480" Margin="10,10,0,0" VerticalAlignment="Top" Width="776">
            <TabItem Header="Banco de dados">
                <Grid Background="#FFE5E5E5">
                    <TextBox HorizontalAlignment="Left" Height="23" Margin="71,44,0,0" TextWrapping="Wrap" Text="{Binding SERVIDOR}" VerticalAlignment="Top" Width="307"/>
                    <Label Content="Servidor:" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
                    <Button Content="Criar banco de dados" HorizontalAlignment="Left" 
                            Margin="40,176,0,0" VerticalAlignment="Top" Width="163"
                            Height="30" Name="cmdCriarBancoDados" Click="cmdCriarBancoDados_Click_1">
                        <Button.BindingGroup>
                            <BindingGroup/>
                        </Button.BindingGroup>
                    </Button>
                    <TextBox HorizontalAlignment="Left" Height="23" Margin="427,43,0,0" TextWrapping="Wrap" Text="{Binding Path=PORTA}" VerticalAlignment="Top" Width="120"/>
                    <TextBox HorizontalAlignment="Left" Height="24" Margin="63,75,0,0" TextWrapping="Wrap" Text="{Binding Path=BANCO_DADOS}" VerticalAlignment="Top" Width="120"/>
                    <ComboBox Name="cboBancoDados"
                        HorizontalAlignment="Left" Margin="112,10,0,0" VerticalAlignment="Top" Width="358"
                              SelectedItem="{Binding Path=NOME_BANCO_DADOS,Converter={StaticResource ResourceKey=nomesDb}}"
                              DisplayMemberPath="Key"
                              
                              ItemsSource="{StaticResource ResourceKey=nomesDb}"
                              SelectedValuePath="Value"
                              /> 
                    <Label Content="Porta:" HorizontalAlignment="Left" Margin="383,41,0,0" VerticalAlignment="Top"/>
                    <Label Content="Banco:" HorizontalAlignment="Left" Margin="13,73,0,0" VerticalAlignment="Top" RenderTransformOrigin="-4.111,-2"/>
                    <Label Content="Banco de dados:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
                </Grid>
            </TabItem>
            <TabItem Header="TabItem">
                <Grid Background="#FFE5E5E5"/>
            </TabItem>
        </TabControl>

    </Grid>
</Page>
E finalmente o code-behind da apresentação.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ClienteWPF
{
    /// <summary>
    /// Interaction logic for ConfiguracaoView.xaml
    /// </summary>
    public partial class ConfiguracaoView : Page
    {
        public ConfiguracaoView()
        {
            InitializeComponent();
        }

        private void Page_Loaded_1(object sender, RoutedEventArgs e)
        {
            DataContext = ClienteWPF.Properties.Settings.Default;
            
        }
    }
}

Eu estou postando após um dia inteiro de tentativas sem sucesso realmente estou sem ideias e nem material para consulta. Até material em inglês eu consultei e nada.

Desde já obrigado pela força.

2 Respostas

M

Cara, você tem de definir um ObjectDataProvider, que é um cara que basicamente você vai usar para definir de onde serão gerados os elementos do seu combobox.
No seu XAML, adicione o seguinte código:

<Page.Resources> <ObjectDataProvider x:Key="confNomesBancoDados " MethodName="GetValues" ObjectType="{x:Type System:Enum}"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="ConfNomesBancoDados " /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> <DicionaryEnumBase x:Key="dicionaryEnumBase"/> </Page.Resources>

Aqui é definido um objeto que será chamado usando confNomesBancoDados e esse objeto encapsula a chamada ao método getValues do Enum ConfNomesBancoDado. Depois é definido um objeto de DictionaryEnumBase, que usaremos para pegar as descrições dos enums e jogar no combobox.

No seu combobox, você deve fazer um binding associando seu enum a propriedade ItemSource do seu combobox. E por último você usa um comboBox.Template para customizar os elementos do combobox com a descrição dos enums

<ComboBox Name="cboBancoDados" HorizontalAlignment="Left" Margin="112,10,0,0" VerticalAlignment="Top" Width="358" SelectedItem="{Binding Path=NOME_BANCO_DADOS,Converter={StaticResource ResourceKey=nomesDb}}" ItemsSource="{StaticResource ResourceKey=confNomesBancoDados }"> <ComboBox.Template> <DataTemplate> <TextBlock Text="{Binding Converter={StaticResource dicionaryEnumBase}}"/> </DataTemplate> <ComboBox.Template/> </ComboBox>

Adicione essas alterações ao seu XAML e veja se resolve seu problema.

K

Ae pessoal do fórum.

Agradeço ao Matheus pela força.

O problema persistiu ainda com o uso de Dicionary então busquei outra forma de fazer o mesmo trabalho vou descrever aqui como foi o procedimento.

1- Troquei Dicionary por apenas ObservableCollection. Então vou armazenar na coleção apenas as descrições do Enum.

2- Tirei IValueConverter da classe DicionaryEnumBase e criei a classe DicionaryConverterBase para executar a conversão.

3- E refiz a vinculação no XAML.

Segue a baixo a nova estrutura.

O Enum
namespace Business.Enum
{
    public enum ConfNomesBancoDados
    {
        [DescriptionAttribute("PostgreSQL 8.5")]
        PostgreSQL,
        [DescriptionAttribute("Firebird 2.5")]
        Firebird,
        [DescriptionAttribute("MySql 3.0")]
        MySql
    }
}

A nova classe DicionaryEnumBase

namespace ClienteWPF
{
    public class DicionaryEnumBase : ObservableCollection<String>
    {
        public DicionaryEnumBase()
        {
        }

        private Type EnumType { get; set; }

        public void Load(Type EnumType)
        {
            this.EnumType = EnumType;
            Array enumValues = Enum.GetValues(EnumType);
            foreach(Object t in enumValues){
                
                //AddChild(new ClienteWPF.DicionaryConverter.ItemMenu(t, GetDescription(t, EnumType)));
                Add(GetDescription(t,EnumType));
                
            }
        }
        
        private string GetDescription(object enumValue, Type enumType)
        {
            var descriptionAttribute = enumType
              .GetField(enumValue.ToString())
              .GetCustomAttributes(typeof(DescriptionAttribute), false)
              .FirstOrDefault() as DescriptionAttribute;


            return descriptionAttribute != null
              ? descriptionAttribute.Description
              : enumValue.ToString();
        }

        public Collection<String> GetLista()
        {
            return this;
        }
    }
}

A classe que estende DicionaryEnumBase para especificarmos qual é o enum que vamos trabalhar.

namespace ClienteWPF.Dicionary
{
    public class ConfNomesBancoDadosDic : DicionaryEnumBase
    {
        public ConfNomesBancoDadosDic()
        {
            Load(typeof(Business.Enum.ConfNomesBancoDados)); 
            
        }
    }
}

E o Novo XAML

<Page x:Class="ClienteWPF.ConfiguracaoView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d"
      xmlns:def="clr-namespace:ClienteWPF"
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:en="clr-namespace:Business.Enum;assembly=Business"
      xmlns:dic="clr-namespace:ClienteWPF.Dicionary"
      xmlns:converters="clr-namespace:ClienteWPF.DicionaryConverter"
      Title="ConfiguracaoView" Loaded="Page_Loaded_1" Width="796.24" Height="500
      ">
    <Page.Resources>
        <ObjectDataProvider x:Key="enumsDB"
                            MethodName="GetLista"
                            ObjectType="{x:Type dic:ConfNomesBancoDadosDic}">
            <ObjectDataProvider.MethodParameters/>
        </ObjectDataProvider>
        <converters:ConfNomesBancoDadosConverter x:Key="nomesDbConverter"/>
    </Page.Resources>
    <Grid>
        <TabControl HorizontalAlignment="Left" Height="480" Margin="10,10,0,0" VerticalAlignment="Top" Width="776">
            <TabItem Header="Banco de dados">
                <Grid Background="#FFE5E5E5">
                    <TextBox HorizontalAlignment="Left" Height="23" Margin="71,44,0,0" TextWrapping="Wrap" Text="{Binding SERVIDOR}" VerticalAlignment="Top" Width="307"/>
                    <Label Content="Servidor:" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
                    <Button Content="Criar banco de dados" HorizontalAlignment="Left" 
                            Margin="40,176,0,0" VerticalAlignment="Top" Width="163"
                            Height="30" Name="cmdCriarBancoDados" Click="cmdCriarBancoDados_Click_1">
                        <Button.BindingGroup>
                            <BindingGroup/>
                        </Button.BindingGroup>
                    </Button>
                    <TextBox HorizontalAlignment="Left" Height="23" Margin="427,43,0,0" TextWrapping="Wrap" Text="{Binding Path=PORTA}" VerticalAlignment="Top" Width="120"/>
                    <TextBox HorizontalAlignment="Left" Height="24" Margin="63,75,0,0" TextWrapping="Wrap" Text="{Binding Path=BANCO_DADOS}" VerticalAlignment="Top" Width="120"/>
                    <TextBox HorizontalAlignment="Left" Height="24" Margin="70" TextWrapping="Wrap" Text="{Binding Path=NOME_BANCO_DADOS}" VerticalAlignment="Top" Width="120"/>

                    <ComboBox x:Name="cboBancoDados"
                    	    HorizontalAlignment="Left" Margin="112,10,0,0" VerticalAlignment="Top" Width="358"
                            SelectedItem="{Binding Path=NOME_BANCO_DADOS, Converter={StaticResource ResourceKey=nomesDbConverter}}"
                            ItemsSource="{Binding Source={StaticResource ResourceKey=enumsDB}}"
                            
                    	>
                        
                    </ComboBox>
                    <Label Content="Porta:" HorizontalAlignment="Left" Margin="383,41,0,0" VerticalAlignment="Top"/>
                    <Label Content="Banco:" HorizontalAlignment="Left" Margin="13,73,0,0" VerticalAlignment="Top" RenderTransformOrigin="-4.111,-2"/>
                    <Label Content="Banco de dados:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
                </Grid>
            </TabItem>
            <TabItem Header="TabItem">
                <Grid Background="#FFE5E5E5"/>
            </TabItem>
        </TabControl>

    </Grid>
</Page>

Espero que essa solução ajude se alguem precisar.

Até a próxima pessoal.

Criado 18 de julho de 2013
Ultima resposta 19 de jul. de 2013
Respostas 2
Participantes 2