Permitir que ligações de interface do usuário aconteçam a partir de propriedades que geram alterações de notificação de qualquer thread que não seja de interface do usuário
Ao vincular propriedades, você sempre deve gerar uma notificação de alteração de propriedade no Thread da interface do usuário ou obterá uma exceção de tempo de execução. Isso faz com que a interface do usuário sangre em seus modelos e modelos de exibição, para que você possa aumentar no thread adequado, o que, por sua vez, impede que você use o INPC de uma biblioteca .NET Standard (a menos que você queira entrar no bait'n'switch) .
Além disso, você pode ter propriedades mudando várias vezes durante um quadro, então você pode pular para o thread de interface do usuário muito mais vezes do que é realmente necessário (tudo o que é necessário é sinalizar a propriedade como "suja" e ser pego no próxima passagem de renderização.
Tudo isso causa complexidade de código significativamente extra e é mais propenso a erros.
Isso também causa um problema no WinUI 3.0, porque agora temos dois threads de interface do usuário: UWP herdado e threads WinUI: em qual devo aumentar?
As preocupações com threads são obviamente válidas, mas não acredito que isso seja realmente um problema no final. Não importa que vários eventos INPC sejam acionados antes das atualizações da interface do usuário, pois apenas o último importaria. Isso não seria diferente do código existente alternando para o Thread de IU várias vezes. Uma vez que o primeiro mude para o UI Thread, a propriedade já pode ter sido atualizada muitas vezes e, portanto, o último em vitórias.
Naturalmente, seria necessário haver um bloqueio curto quando o valor é lido para impedir que o sinalizador sujo seja definido, portanto, uma segunda rodada de atualizações da interface do usuário ocorre no próximo quadro, caso a propriedade seja atualizada ao mesmo tempo em que está sendo lida.
Na verdade, se um valor, por exemplo, mudar de falso, para verdadeiro e de volta para falso, a propriedade de dependência já é inteligente o suficiente para detectar que o valor não foi alterado e pode otimizar não causando uma nova passagem de renderização devido à propriedade não mudança.
Esta é uma preocupação muito válida, obrigado por levantar. Suporte de afinidade de thread para DPs no framework pode não ser um grande problema, mas pode muito bem ser para implementadores do INPC.
Se algum código for capaz de gerar uma alteração de propriedade de um thread que não seja da interface do usuário, isso também significa que o código de suporte da propriedade pode ser alterado de um thread em segundo plano. Ele pode ser protegido usando bloqueios, mas as ligações bidirecionais podem se tornar um problema, pois podem tornar as cadeias de alteração de propriedade impasses.
Há também o maior problema do INPC, que é a falta de valor "atual" quando o evento foi levantado. Pode haver situações em que as propriedades não sejam sincronizadas corretamente (por exemplo, SelectedIndex
e ItemsSource
não são atualizados de forma síncrona e SelectedIndex
perde seu valor), ou com ping-pongs de alterações causadas por estados de propriedade (por exemplo, alterações TextBox e filtros regex).
Isso traz então os problemas com o INCC, onde todo o acervo precisa ser protegido adequadamente. Por exemplo, você pode gerar um evento referenciando um item que foi movido ou não está mais lá.
Não estou dizendo que não há solução para esse problema (certamente há), mas os ouvintes do IPNC encadeando as alterações de afinidade não são suficientes para facilitar esse problema em ambas as extremidades da interface.
O WPF descobriu isso, então talvez apenas puxe a solução de lá?
Ótima sugestão. Fazemos isso para eventos CollectionChanged (um pouco por acidente...), devemos ser capazes de fazer o mesmo para NotifyPropertyChanged.
Comentários muito úteis
Esta é uma preocupação muito válida, obrigado por levantar. Suporte de afinidade de thread para DPs no framework pode não ser um grande problema, mas pode muito bem ser para implementadores do INPC.
Se algum código for capaz de gerar uma alteração de propriedade de um thread que não seja da interface do usuário, isso também significa que o código de suporte da propriedade pode ser alterado de um thread em segundo plano. Ele pode ser protegido usando bloqueios, mas as ligações bidirecionais podem se tornar um problema, pois podem tornar as cadeias de alteração de propriedade impasses.
Há também o maior problema do INPC, que é a falta de valor "atual" quando o evento foi levantado. Pode haver situações em que as propriedades não sejam sincronizadas corretamente (por exemplo,
SelectedIndex
eItemsSource
não são atualizados de forma síncrona eSelectedIndex
perde seu valor), ou com ping-pongs de alterações causadas por estados de propriedade (por exemplo, alterações TextBox e filtros regex).Isso traz então os problemas com o INCC, onde todo o acervo precisa ser protegido adequadamente. Por exemplo, você pode gerar um evento referenciando um item que foi movido ou não está mais lá.
Não estou dizendo que não há solução para esse problema (certamente há), mas os ouvintes do IPNC encadeando as alterações de afinidade não são suficientes para facilitar esse problema em ambas as extremidades da interface.