Como posso criar um personalizado * write-only * dependência-propriedade?
-
19-09-2019 - |
Pergunta
Eu preciso saber qual é o procedimento para fazer uma dependência da propriedade somente para gravação. Eu posso ver que a classe DependencyProperty não tem um método especial "Register" para propriedades somente gravação, mas não tenho idéia se o método RegisterAttached pode aplicar-se o que estou tentando fazer.
Esta propriedade precisa ser uma dependência da propriedade, em vez de uma propriedade CLR simples. Internamente, minha classe requer um PropertyChangedCallback nesta propriedade, a fim de permanecer estável.
Eu sei que a dependência-propriedades somente gravação pode ser criado, pois afirma-se claramente em:
Pro C # 2008 eo .NET 3.5 Platform , página 1061 .
No entanto, este é o único lugar onde eu posso até achar "propriedade de dependência" e "escrever apenas" na mesma página. E este autor, aparentemente, não acho que era necessário para realmente mostrar ao leitor o procedimento para outra coisa senão uma leitura-escrita dependência-propriedade básica. Claro, este livro pode ser uma carga de BS - mas este livro analisa bastante normal, então eu acho que é uma aposta bastante segura de que o autor está correta. Presumo que a falta de informação na internet decorre do fato de que ninguém geralmente precisa fazer uma propriedade como esta.
Eu sei que parece muito questionável querer fazer o seu próprio só de escrita dependência-propriedade. Eu lhe asseguro que faz sentido onde eu o quero. Minha classe tem uma propriedade cujo valor só é útil ao defini-lo objeto. Se outro objeto foram para solicitar o valor dessa propriedade mais tarde, não seria capaz de fazer qualquer sentido racional fora do valor sem conhecer o contexto original do setter.
Esta propriedade não se destina a ser utilizado para fins informativos. Deixando objetos fora tentar usar o valor da propriedade desta forma é problemático, perigosa e um risco de segurança. Então eu acredito que o melhor projeto é proibir operações de leitura sobre essa propriedade. Quem estiver usando minha classe vai achar que eles são forçados a usar a classe a forma como foi concebido, que vai funcionar muito melhor e mais limpa no final.
Solução
Você não pode, este parece ser por design. Embora eu possa compreender a sua abordagem para o mencionado livro e estou em nenhuma maneira a questionar a sua qualidade, eu ainda presumir que isso seja algum tipo de copiar e colar ou problema semelhante. Aqui está o meu raciocínio:
WPF código de sistema de propriedade
- Como você já mencionou a API pública do DependencyProperty Classe apenas características RegisterReadOnly () RegisterAttachedReadOnly () .
- Speluncing nas partes internas de classe via refletor só revela código dedicado para lidar com estes Read-Only Dependency Propriedades , não há nada à vista sobre write apenas a funcionalidade.
- Outra opção poderia ter sido metadados, mas nem Propriedade de Dependência Metadados nem em particular Framework propriedade Metadados por meio do FrameworkPropertyMetadataOptions enumeração está fornecendo qualquer coisa ao longo das linhas de somente gravação.
projeto WPF sistema de propriedade
- Mais importante, 'A atual implementação do WPF do seu processador XAML é inerentemente propriedade de dependência consciente. Os métodos WPF XAML sistema utiliza processadores propriedades para as propriedades de dependência de carga quando binário XAML e processamento de atributos que são as propriedades de dependência. Isso ignora efetivamente os invólucros de propriedade. ', consulte XAML Carregando e Dependência propriedades .
- O mais importante, 'As propriedades de dependência geralmente deve ser considerado como propriedades públicas. A natureza dos impede que o Windows Presentation Foundation (WPF) sistema de propriedade a capacidade de fazer garantias de segurança sobre um valor de propriedade de dependência. ', consulte Dependência Segurança Patrimonial .
Especialmente os dois últimos pontos são delineando a restrição de design, que os valores de propriedade de dependência são sempre acessível através de GetValue () / SetValue () , não importa se os seus invólucros CLR são de acesso restrito ou disponíveis em tudo, com a única exceção sendo o especificamente responsável por Read-Only Dependency Properties .
Por conseguinte, como Jeffs resposta já implica, apenas removendo o getter por exemplo, não realmente impedir que alguém acessando a propriedade através de GetValue () , embora isso possa, pelo menos, 'reduzir o namespace imediatamente exposta de uma classe personalizada' . A utilidade de qualquer solução alternativa semântica de fazer o propevalor rty um pouco menos visível / acessível e o valor recuperado inerentemente inútil para clientes como sugerido por Jeff depende do seu cenário em particular, é claro.
Outras dicas
Interessante, este é definitivamente um cenário raro, eu estaria interessado em ouvir mais no que ele permite.
Você consideraria a idéia de fornecer um valor inválido (como null) para leituras através da ligação ou GetValue, enquanto que apenas não ter um getter CLR?
Utilize uma DependencyProperty privada para armazenar o valor "real" você se preocupa, ou apenas uma variável de membro particular.
Na propriedade mudou de retorno de chamada, sempre reverter o valor de volta para o valor original, enquanto armazenar afastado o novo valor que foi definido.
Passo a maior parte do meu tempo fazendo o desenvolvimento de controle Silverlight agora, para esta propriedade funciona em WPF e Silverlight da terra, e não usa coercian ou diversão qualquer coisa assim. Talvez você fica indo no caminho certo, no entanto.
/// <summary>
/// Sets the write-only dependency property.
/// </summary>
public string MyWriteOnlyDependencyProperty
{
set { SetValue(MyWriteOnlyDependencyPropertyProperty, value); }
}
private string _theRealSetValue;
private bool _ignorePropertyChange;
/// <summary>
/// Identifies the MyWriteOnlyDependencyProperty dependency property.
/// </summary>
public static readonly DependencyProperty MyWriteOnlyDependencyPropertyProperty =
DependencyProperty.Register(
"MyWriteOnlyDependencyProperty",
typeof(string),
typeof(TemplatedControl1),
new PropertyMetadata(null, OnMyWriteOnlyDependencyPropertyPropertyChanged));
/// <summary>
/// MyWriteOnlyDependencyPropertyProperty property changed handler.
/// </summary>
/// <param name="d">TemplatedControl1 that changed its MyWriteOnlyDependencyProperty.</param>
/// <param name="e">Event arguments.</param>
private static void OnMyWriteOnlyDependencyPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TemplatedControl1 source = d as TemplatedControl1;
if (source._ignorePropertyChange)
{
source._ignorePropertyChange = false;
return;
}
string value = e.NewValue as string;
source._theRealSetValue = value;
// Revert, since this should never be accessible through a read
source._ignorePropertyChange = true;
source.SetValue(e.Property, e.OldValue);
}
Parece que você pode usar o CoerceValueCallback
associada com a propriedade através da FrameworkPropertyMetadata
aplicada na definição de propriedade de dependência. Basta instalar um callback que leva o segundo argumento, o novo valor, passa para o objeto através do seu próprio mecanismo só de escrita, em seguida, retorna null
(ou para tipos de valor, default(T)
).
É verdade que ".NET lembra o valor original antes da coerção", mas não vai ser propagada através de ligação de dados. Chamadas para GetValue
irá retornar o valor coagido, que não faz nada vazamento.
Eu estou usando isso para implementar setters conveniência de sentido único para o valor da minha propriedade primária, que é uma seqüência de bytes. Um utilizador pode ligar-se uma cadeia de caracteres, por exemplo, para definir a propriedade principal para os bytes codificados ASCII (ou UTF-8, dependendo do que é propriedade conjunto). Mas nem todas as seqüências de bytes são válidos UTF-8, por isso não é possível reverter a conversão e ler um back corda através do estabelecimento de conveniência.
public string AsciiData
{
set { BinaryArray = Encoding.ASCII.GetBytes(value); }
}
public static readonly DependencyProperty AsciiDataProperty =
DependencyProperty.Register("AsciiData",
typeof(string),
typeof(HexView),
new FrameworkPropertyMetadata(null, CoerceAsciiData));
private static object CoerceAsciiData(DependencyObject target, object value)
{
(target as HexView).AsciiData = value as string;
return null;
}
O manipulador de coerção podem ser removidos através de substituição de metadados, de modo que este não está fornecendo segurança , mas vai impedir que os desenvolvedores acidentalmente criando acoplamento de maneiras erradas.
Estou confuso sobre o porquê você não pode simplesmente ter o 'ficar' nada de retorno útil?
Mas, além disso, talvez você simplesmente não implementar o 'OnMyWriteOnlyDependencyPropertyPropertyChanged', no exemplo de Jeff.
Não há razão real para ter o evento, se ninguém pode lê-lo, certo?