WPF: DataGrid editável e um ObservableDictionary

Por omissão não está incluído nenhum dicionário observável no WPF, mas seria bastante útil ter um para usar numa DataGrid editável. Neste artigo vamos fazer um pouco de “batota” e dar uso à ObservableCollection para criar um novo tipo parecido ao de um dicionário observável.

Não podem usar directamente um dicionário numa DataGrid editável, porque os KeyValuePairs são apenas de leitura e não implementam a interface INotifyPropertyChanged.

Mas ao criar uma nova classe para pares e herdando a ObservableCollection podemos imitar o comportamento de um dicionário observável.

Uma classe par observável

Começamos pela classe que vai guardar o par chave/valor:

public class Pair<TKey, TValue> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected TKey _key;
    protected TValue _value;
 
    public TKey Key
    {
        get { return _key; }
        set
        {
            if (
                (_key == null && value != null)
                || (_key != null && value == null)
                || !_key.Equals(value))
            {
                _key = value;
                NotifyPropertyChanged("Key");
            }
        }
    }
 
    public TValue Value
    {
        get { return _value; }
        set
        {
            if (
                (_value == null && value != null)
                || (_value != null && value == null)
                || (_value != null && !_value.Equals(value)))
            {
                _value = value;
                NotifyPropertyChanged("Value");
            }
        }
    }
}

Incluímos construtores e métodos:

public class Pair<TKey, TValue> : INotifyPropertyChanged
{
    public Pair()
    {
    }
 
    public Pair(TKey key, TValue value)
    {
        Key = key;
        Value = value;
    }
 
    public Pair(KeyValuePair<TKey, TValue> kv)
    {
        Key = kv.Key;
        Value = kv.Value;
    }
 
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Colecção de pares observável

Podemos agora criar um novo tipo de colecção observável semelhante a um dicionário:

public class ObservablePairCollection<TKey, TValue> : ObservableCollection<Pair<TKey, TValue>>
{
    public ObservablePairCollection()
        : base()
    {
    }
 
    public ObservablePairCollection(IEnumerable<Pair<TKey, TValue>> enumerable)
        : base(enumerable)
    {
    }
 
    public ObservablePairCollection(List<Pair<TKey, TValue>> list)
        : base(list)
    {
    }
 
    public ObservablePairCollection(IDictionary<TKey, TValue> dictionary)
    {
        foreach (var kv in dictionary)
        {
            Add(new Pair<TKey, TValue>(kv));
        }
    }
 
    public void Add(TKey key, TValue value)
    {
        Add(new Pair<TKey, TValue>(key, value));
    }
}

Não precisam de parar por aqui. Não é muito difícil implementar a interface IDictionary e ter um dicionário de “verdade”, mas em muitos casos esta solução é suficiente.

Usar uma DataGrid editável

Vamos fazer uso disto numa DataGrid editável.

Declarem a propriedade no vosso view model:

readonly ObservablePairCollection<string, string> _countries;

public ObservablePairCollection<string, string> Countries { get { return _countries; } }

E criem alguns dados para testes:

public MainWindowViewModel()
{
    _countries = new ObservablePairCollection<string, string>();
    _countries.Add("Ascension Island", "AC");
    _countries.Add("Andorra", "AD");
    _countries.Add("United Arab Emirates", "AE");
    _countries.Add("Afghanistan", "AF");
    _countries.Add("Antigua and Barbuda", "AG");
    // etc.
}

Incluam o controlo no XAML:

<DataGrid ItemsSource="{Binding Countries}" />

O resultado é o seguinte:

DataGrid editável com uma colecção de pares observável
DataGrid editável com uma colecção de pares observável
Nuno Freitas
Publicado por Nuno Freitas em 21 março, 2014

Artigos relacionados