Search code examples
wpflistboxupdatesobservablecollection

Updating values in ObservableCollection


Hey I have an ObservableCollection which consists of a class with two attributes (strings = User and Response) bound to a listbox.

I would like to have the users in the listbox first, which I add with this:

for (int i = 0; i < ArrStrUser.Length; i++)
{
  Users.Add(new User() { input = ArrStrUser[i].Trim() });              
}

I want to add the responses to the respective user later. If I do this, they will be added to the ObservableCollection but not update in the listbox.

Users[i].response = strOutput.Trim().Replace(Environment.NewLine, " ");

The ObservableCollecton

private ObservableCollection<Input> Users = new ObservableCollection<Input>();

The Class:

public class Input
{
 public string user{ get; set; }
 public string response { get; set; }
}

XAML:

<ListBox x:Name="LBresponse" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" ItemTemplate="{StaticResource UserTemplate}" />

<DataTemplate x:Key="UserTemplate">
  <StackPanel Orientation="Horizontal">
    <TextBlock Text="{Binding Path= user}" Width="50"/>
      <TextBlock Text="{Binding Path= response}" />
    <Button Content="Delete" Click="DeleteUser_Clicked" HorizontalAlignment="Left"/>
  </StackPanel>
</DataTemplate>

Solution

  • Simple solution

    Your Input class needs to implement the INotifyPropertyChanged interface and invoke the PropertyChanged event upon changing property's value in order to update the ListBox. The ObservableCollection only "cares" about adding or removing items, it doesn't handle item's property changing.

    Try editing your input class like this:

    public class Input : INotifyPropertyChanged
    {
        public string user{ get; set; }
    
        private string _response;
        public string Response{
            get => _response;
            set {
                _response = value;
                NotifyPropertyChanged();
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
     
        protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    Now changing the Response property should update the UI.


    Better solution

    I'd also advise you to separate the INotifyPropertyChanged implementation into its own class if you want to use it somewhere else, too. Or better yet, use a library that already has it, like the mvvm-helpers nuget package by James Montemagno.

    Here's a link to the INotifyPropertyChanged implementation from that library

    This is how you use it:

    public class Input : ObservableObject
    {
        public string user{ get; set; }
    
        private string _response;
        public string Response{
            get => _response;
            set => SetProperty(ref _response, value);
        }
    }
    

    It also supports passing in an OnChanged Action and a validation function.