Digamos que eu tenha as duas caixas de combinação a seguir (todas pseudocódigo):
<ComboBox Data="@AllLastNames" @bind-Value="@LastName"/>
<ComboBox Data="@AllFirstNames" @bind-Value="@FirstName"/>
E o código por trás é:
private string LastName { get; set; }
private string FirstName { get; set; }
private List<string> AllLastNames => _allLastNames;
private List<string> AllFirstNames => _firstNameDictionary[LastName];
Ok, tudo o que foi dito acima funcionará muito bem se o Blazor, nos momentos apropriados, obtiver AllFirstNames
, ver que ele mudou por meio de uma comparação de igualdade de referência e chamar SetParameteraAsync()
com o novo valor.
Então, quando/por que e como o Blazor decide verificar essas Data=
propriedades para ver se elas foram alteradas?
Este é um caso em que, dentro do LastName
setter, devo ligar StateHasChanged()
?
Como e por que o Blazor decide atualizar o estado pode ser considerado uma mágica ou uma caixa preta ( mais sobre estados ).
Mas se você estiver interessado em saber em que casos funciona, posso dar os seguintes exemplos.
O estado é atualizado automaticamente :
OnInitialized
,OnParametersSet
,ShouldRender
,OnAfterRender
, etc.)Você precisa atualizar o estado manualmente :
No seu caso
@bind-Value="@LastName"
funciona como uma trigger para atualizar automaticamente o estado, por exemplo quando o usuário seleciona um item noComboBox
AllLastNames
, toda a cadeia é atualizada, ou sejaLastName
,AllFirstNames
eComboBox
AllFirstNames
sem chamarStateHasChanged
o .Notas: Esta é minha preferência pessoal, mas pela minha experiência, usar um dicionário sem verificar a existência pode levar a um erro e muitas vezes é difícil encontrar a fonte.
Eu sugeriria verificar a existência (mesmo se você tiver certeza de que ela existe):
Não há magia negra envolvida.
Quando a renderização instancia um componente, ela cria e mantém uma lista das propriedades mapeadas para esse componente. Ele gera o
ParameterView
objeto desta lista quando chamaSetParametersAsync
.Quando o Renderizador renderiza um componente, ele verifica se o estado foi alterado em algum parâmetro do subcomponente. Se sim, ele chama
SetParametersAsync
o subcomponente.Nota que afirmo: "Chama
SetParametersAsync
", não "renderiza o componente". Se o componente for umComponentBase
componente, então será. Existem outros componentes da biblioteca de componentes de terceiros que podem substituirSetParametersAsync
e implementar lógicas diferentes que não acionam um arquivoStateHasChanged
.O algoritmo aplicado a cada valor para detectar uma alteração é o seguinte:
Basicamente, ele pode detectar alterações em primitivos e em alguns objetos de valor. Para todo o resto
MayHaveChanged
retornatrue
[não se arrisca]. Observe que callbacks e RenderFragments são objetos de referência, então returntrue
.No seu caso
List<string> AllLastNames
é um tipo de referência, então falha no teste eMayHaveChanged
retornatrue
. Portanto, se o componente pai forComboBox
renderizado, o renderizadorSetParametersAsync
chamaráComboBox
.Adicione o manipulador de eventos, por exemplo, OnChange à sua caixa de combinação que atualizará a lista de referência com novos dados do banco de dados ou de alguma outra fonte que você esteja usando
Toda vez que este componente é renderizado, e isso deve acontecer quando o LastName for alterado.
Data="@AllFirstNames"
é um 'parâmetro complexo' no Blazor, o que significa que sempre será tratado como alterado.