Following the MVVM model, I am not able to update the values of a variable of an object in a collection, display them on the screen or the user type and this value is passed to the variable.
In my case, I have a customer registration screen and this client can contain more than one address. Well, a control of type ItemsControl
receives in the ItemsSource
Binding
attribute of the Endereços
collection and in the DataTemplate
attribute the layout of each ItemControl(endereço)
and each field with its Binding
.
Follow the codes for a better understanding:
ViewModel
public class ClienteViewModel : INotifyPropertyChanged
{
public ClienteViewModel()
{
Enderecos = new ObservableCollection<EnderecoViewModel>();
}
private ObservableCollection<EnderecoViewModel> _enderecos;
public ObservableCollection<EnderecoViewModel> Enderecos
{
get { return _enderecos; }
set
{
_enderecos = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
XAML
<ItemsControl ItemsSource="{Binding Path=Enderecos, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type endereco:EnderecoViewModel}">
<TextBlock Text="CEP:"/>
<xctk:MaskedTextBox Mask="00000-000" TextChanged="TbCep_OnTextChanged" Text="{Binding Cep}" Tag="{Binding EnderecoId}"/>
<TextBlock Text="Logradouro"/>
<TextBox Text="{Binding Logradouro}"/>
<TextBlock Text="Número:" />
<TextBox Text="{Binding Numero}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
XAML.cs
private void TbCep_OnTextChanged(object sender, TextChangedEventArgs e)
{
var enderecoOnList =
_clienteViewModel.Enderecos.FirstOrDefault(
x =>
x.EnderecoId == Guid.Parse(sender.GetType().GetProperty("Tag").GetValue(sender).ToString()));
var endereco = new Endereco();
if (enderecoOnList != null && enderecoOnList.Cep != null)
{
var cep = enderecoOnList.Cep.Replace("-", "");
if (cep.Length == 8)
{
endereco = BuscarEnderecoPorCep(cep);
if (endereco != null)
{
enderecoOnList.Logradouro = endereco.Logradouro;
enderecoOnList.Complemento = endereco.Complemento;
enderecoOnList.Bairro = endereco.Bairro;
enderecoOnList.Cidade = endereco.Cidade;
enderecoOnList.Estado = endereco.Estado;
enderecoOnList.CodigoIbge = endereco.CodigoIbge;
enderecoOnList.Pais = "Brasil";
}
}
}
}
When this "TbCep_OnTextChanged"
event is triggered, the enderecoOnList
variable is given the correct position address, but all variables are set to null
, including the user-entered ZIP code on the screen.
When I change any variable of an address object via the screen, the Addresses collection does not receive this value in that position or in another position in the collection.
NOTE: I have a add button, which adds a new address object to the Addresses collection, and the Binding normally occurs on the screen. I also have a remove button, which removes an address object from the Addresses collection, which also works perfectly. That is, binding bound to Addresses works, however the Binding bound to a variable of an Address object in the Addresses collection does not work.
How can I solve this problem, I tried to set Binding Mode as TwoWay, but I still did not succeed, or what to fix in my code?