Updating a collection object’s values via Binding WPF, MVVM

Asked

Viewed 402 times

4

Following MVVM model, I am not able to update the values of a variable of an object in a collection, show them on the screen or the user type and this value be passed to the variable.

In my case, I have a customer registration screen and this client may contain more than one address. Well, a control of the type ItemsControl receives in attribute ItemsSource the Binding of the collection Endereços and in the attribute DataTemplate the layout of each ItemControl(endereço) and each field with its respective Binding.

Follow the codes for 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 event "TbCep_OnTextChanged" is triggered, the variable enderecoOnList receives the address of the right position, but all variables are set as null, including the zip code entered by the user on the screen.

When I change any variable of an address object via screen, the Addresses collection does not receive this value at that position or at another collection position.

NOTE: I have an add button, which adds a new address object to the Addresses collection and occurs Binding normally on the screen. I also have a remove button, which removes an address object from the Addresses collection, which also works perfectly. That is, the Binding connected to Addresses works, but the Binding linked to a variable of a collection address object does not work.

How can I solve this problem, I have tried to set the Binding Mode as Twoway, but I have not yet succeeded, or what to fix in my code?

1 answer

2


Good people, I managed to solve this my problem after some time more study. As I myself quoted in the question above, the Binding in the collection Endereços worked perfectly, that at the same time in their children endereço will not occur the Binding of their variables. Thinking and focusing on this problem, we can notice that each child endereço also need to implement the class INotifyPropertyChanged and call the method OnPropertyChanged that is triggered to update the property on the screen. Where I did not previously.

Follow the code of the class endereço

Viewmodel

public class CreateClienteEnderecoViewModel : INotifyPropertyChanged
    {
        public CreateClienteEnderecoViewModel()
        {
            EnderecoId = Guid.NewGuid();
        }

        #region Properties
        public Guid EnderecoId { get; set; }

        private string _logradouro;
        public string Logradouro
        {
            get { return _logradouro; }
            set
            {
                _logradouro = value;
                OnPropertyChanged();
            }
        }

        private string _numero;
        public string Numero
        {
            get { return _numero; }
            set
            {
                _numero = value;
                OnPropertyChanged();
            }
        }

        #endregion
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

I hope to help more people because it took me a long time to find a solution to this problem! Thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.