Compartilhar via


Propriedade de Dependência de Tipos de Coleção

Este tópico fornece orientação e padrões sugeridos para como implementar uma propriedade de dependência na qual o tipo da propriedade é um tipo de coleção.

Este tópico contém as seguintes seções.

  • Implementando uma propriedade de dependência do tipo coleção
  • Inicializando a coleção além do valor padrão
  • Reportando Alterações de Vínculo de Valores a partir de Propriedades de Coleção
  • Tópicos relacionados

Implementando uma propriedade de dependência do tipo coleção

Para um propriedade de dependência em geral, a implementação padrão que você segue é que você define um invólucro de propriedade CLR, no qual essa propriedade é feita por um identificador DependencyProperty em vez de um campo ou outra construção. Você segue esse mesmo padrão quando você implementa uma propriedade do tipo coleção. No entanto, uma propriedade do tipo coleção apresenta alguma complexidade ao padrão sempre que o tipo que está contido dentro da coleção é por si mesmo uma classe derivada de DependencyObject ou Freezable.

Inicializando a coleção além do valor padrão

Quando você cria um propriedade de dependência, você não especifica o valor padrão da propriedade como a valor do campo inicial. Em vez disso, você especifica o valor padrão por meio de metadados da propriedade de dependência. Se a propriedade for um tipo de referência, o valor padrão especificado em metadados da propriedade de dependência não é um valor padrão por instância; em vez disso é um valor padrão que se aplica a todas as instâncias do tipo. Portanto, você deve ter cuidado para não usar a coleção estática singular definida pelos metadados da propriedade de coleção como o valor padrão de trabalho para instâncias recém-criadas do seu tipo. Em vez disso, você deve verificar que você deliberadamente define o valor da coleção como uma coleção exclusiva (instância) como parte de sua lógica de construtor de classe. Caso contrário, você terá criado uma classe Singleton não intencional.

Considere o exemplo a seguir: A seção a seguir do exemplo mostra a definição de uma classe Aquarium. A classe define a propriedade de dependência de tipo coleção AquariumObjects, que usa o tipo genérico List<T> com uma restrição de tipo FrameworkElement. Na chamada a Register(String, Type, Type, PropertyMetadata) para o propriedade de dependência, os metadados estabelecem o valor padrão para um novo List<T> genérico.

public class Fish : FrameworkElement { }
public class Aquarium : DependencyObject
{
    private static readonly DependencyPropertyKey AquariumContentsPropertyKey = 
        DependencyProperty.RegisterReadOnly(
          "AquariumContents",
          typeof(List<FrameworkElement>),
          typeof(Aquarium),
          new FrameworkPropertyMetadata(new List<FrameworkElement>())
        );
    public static readonly DependencyProperty AquariumContentsProperty =
        AquariumContentsPropertyKey.DependencyProperty;

    public List<FrameworkElement> AquariumContents
    {
        get { return (List<FrameworkElement>)GetValue(AquariumContentsProperty); }


...


}

Entretanto, se você apenas deixa o código como mostrado, aquele valor padrão de lista é compartilhado para todas as instâncias de Aquarium. Se você executasse o código de teste a seguir, que destina-se a mostrar como você instanciaria duas instâncias separadas de Aquarium e adicionaria um único Fish diferente para cada um deles, você veria um resultado surpreendente:

Aquarium myAq1 = new Aquarium();
Aquarium myAq2 = new Aquarium();
Fish f1 = new Fish();
Fish f2 = new Fish();
myAq1.AquariumContents.Add(f1);
myAq2.AquariumContents.Add(f2);
MessageBox.Show("aq1 contains " + myAq1.AquariumContents.Count.ToString() + " things");
MessageBox.Show("aq2 contains " + myAq2.AquariumContents.Count.ToString() + " things");

Em vez de cada coleção ter uma contagem de um, cada conjunto possui uma contagem de dois! Isso ocorre porque cada Aquarium adicionou seu Fish à coleção de valor padrão, que resultou de uma única chamada a construtor nos metadados e, portanto, é compartilhado entre todas as instâncias. Essa situação quase nunca é o que você deseja.

Para corrigir esse problema, você deve limpar o valor da coleção da propriedade de dependência para uma instância única, como parte da chamada ao construtor da classe. Como a propriedade é uma propriedade de dependência somente-leitura, você usa o método SetValue(DependencyPropertyKey, Object) para defini-la, usando a DependencyPropertyKey que só está acessível dentro da classe.

public Aquarium() : base()
{
    SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>()); 
}

Agora, se você executasse novamente esse mesmo código de teste, você poderia ver resultados mais esperados, onde cada Aquarium suportaria sua própria coleção única.

Haveria uma variação pequena nesse padrão se você optasse que sua propriedade de coleção fosse de leitura-e-gravação. Nesse caso, você poderia chamar o acessor set público a partir do construtor para fazer a inicialização, o que ainda assim seria chamar a assinatura sem-chave de SetValue(DependencyProperty, Object) dentro de seu invólucro set, usando um identificador DependencyProperty público.

Reportando Alterações de Vínculo de Valores a partir de Propriedades de Coleção

Uma propriedade de coleção que é por si própria uma propriedade de dependência não relata automaticamente alterações para suas subpropriedades. Se você estiver criando vínculos em uma coleção, isso pode impedir que a vinculação relate alterações, portanto invalidando alguns cenários de associação de dados. No entanto, se você usar o tipo de coleção FreezableCollection<T> como o tipo de coleção, então alterações de subpropriedades em elementos contidos na coleção são relatados corretamente, e a vinculação funciona conforme esperado.

Para habilitar vinculação de subpropriedade em uma coleção de objetos de dependência, crie a propriedade de coleção como tipo FreezableCollection<T>, com uma restrição de tipo para essa coleção para qualquer classe derivada de DependencyObject.

Consulte também

Conceitos

XAML e classes personalizadas

Revisão de Associação de Dados

Visão geral sobre propriedades de dependência

Propriedades de Dependência Personalizada

Metadados de Propriedade de Dependência

Referência

FreezableCollection<T>