ListView not updating after ObservableCollection is changed

16,056

Solution 1

The problem is that you're setting the _forecastList to a new instance of an ObservableCollection. Just do this:

public WeatherForcastViewModel()
{

    _forcastList = new ObservableCollection<ForcastInfo>();
    //Callback from MainView ,forcast data is available
    Messenger.Default.Register<GoToForcast>
   (
        this, (action) => MessageFromMain(action)
   );
}


private void MessageFromMain(GoToForcast message)
{
    //This should work but its not working
    ForcastInfo forcast = new ForcastInfo();
    forcast.Condition = "clear";
    forcast.Day = "Sunday";
    forcast.High = "70";
    forcast.Low = "50";
    //_forcastList = new ObservableCollection<ForcastInfo>(); <---- this is messing you up
    ForcastList.Add(forcast);
    ForcastList.Add(forcast);
    ForcastList.Add(forcast);
    ForcastList.Add(forcast);
    ForcastList.Add(forcast);
    ForcastList.Add(forcast);

    //ForcastList = message.ForcastList;
}

Solution 2

Well, you change the object the list property references and do not tell the view about it by setting the field to a new collection in that method.

Either only use the property and comment in the notifications in the setter or just make it impossible to change the reference, which often is the best method:

private readonly ObservableCollection<ForcastInfo> _forcastList = new ObservableCollection<ForcastInfo>();
public ObservableCollection<ForcastInfo> ForcastList
{
    get { return _forcastList; }
}

Now you cannot mess up bindings as the property always points to the same object. To replace the list with this setup just call Clear() on it and add the new objects.

Share:
16,056
sachin saner
Author by

sachin saner

I work for Reval.com and did Masters in Computer Science from State University of NY , Binghamton. I like to program in C++and C# . I am interested in improving my competencies in WPF programming , learning more about OO Design patterns and Concurrent programming

Updated on June 17, 2022

Comments

  • sachin saner
    sachin saner about 2 years

    I have a ListView which i am updating as soon as i get data . ListView gets updated if i add items to observableCollection in the ViewModel`s constructor but not if i do it in some method after i get callback .

    I have spend a lot of time on Stackoverflow and i know there are many related questions but i could not find answer . Whats bugging me is that , if it works when i add values in the constructor then why it doesnt work if i add values in the some method .

    • I am using ObservableCollection
    • Setting DataContext
    • Binding ObservableCollection to ListView in XAML

    here is the XAML code

    <UserControl x:Class="WFP_Illustrated.UserControls.WeatherForcastControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             >
    <UserControl.Resources>
        <Style TargetType="TextBlock" x:Key="TextStyle">
            <Setter Property="FontFamily" Value="Adobe Caslon Pro"/>
            <Setter Property="FontSize" Value="18"/>
            <Setter Property="MinWidth" Value="60"/>
        </Style>
        <DataTemplate x:Key="ForcastTemplate">
            <Border BorderBrush="Aqua" BorderThickness="1" Padding="5" Margin="5">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
    
                    <TextBlock Grid.Row="0" Grid.ColumnSpan="2" Text="{Binding Path= Day}" Style="{StaticResource TextStyle}"/>
                    <TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding Path= Condition}"   Style="{StaticResource TextStyle}"/>
                    <Image Grid.Row="1" Grid.Column="1" />
                    <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding Path= Low}"  Style="{StaticResource TextStyle}"/>
                    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path= High}"  Style="{StaticResource TextStyle}"/>
                </Grid>
            </Border>
        </DataTemplate>
    </UserControl.Resources>
    <Grid>
        <ListView Name="ForcastList"
                 ItemTemplate="{StaticResource ForcastTemplate}"
                 ItemsSource="{Binding ForcastList}"
                 Background="SlateGray"
                 >
    
        </ListView>
    </Grid>
    

    XAML CodeBehind

    public partial class WeatherForcastControl : UserControl
    {
        private WeatherForcastViewModel _viewModel;
        public WeatherForcastControl()
        {
            InitializeComponent();
            _viewModel = new WeatherForcastViewModel();
            this.DataContext = _viewModel;
        }
    }
    

    Here is ModelView Code

      private ObservableCollection<ForcastInfo> _forcastList;
        public ObservableCollection<ForcastInfo> ForcastList
        {
            get { return _forcastList; }
            //set
            //{
            //    _forcastList = value;
            //    OnPropertyChanged("ForcastList");
            //}
        }
    
        public WeatherForcastViewModel()
        {
            //If this is uncommented , I will see values in ListView
            //ForcastInfo forcast = new ForcastInfo();
            //forcast.Condition = "clear";
            //forcast.Day = "Sunday";
            //forcast.High = "70";
            //forcast.Low = "50";
            //_forcastList = new ObservableCollection<ForcastInfo>();
            //ForcastList.Add(forcast);
            //ForcastList.Add(forcast);
            //ForcastList.Add(forcast);
            //ForcastList.Add(forcast);
            //ForcastList.Add(forcast);
            //ForcastList.Add(forcast);
    
            //Callback from MainView ,forcast data is available
            Messenger.Default.Register<GoToForcast>
           (
                this, (action) => MessageFromMain(action)
           );
        }
    
        private void MessageFromMain(GoToForcast message)
        {
            //This should work but its not working
            ForcastInfo forcast = new ForcastInfo();
            forcast.Condition = "clear";
            forcast.Day = "Sunday";
            forcast.High = "70";
            forcast.Low = "50";
            _forcastList = new ObservableCollection<ForcastInfo>();
            ForcastList.Add(forcast);
            ForcastList.Add(forcast);
            ForcastList.Add(forcast);
            ForcastList.Add(forcast);
            ForcastList.Add(forcast);
            ForcastList.Add(forcast);
    
            //ForcastList = message.ForcastList;
        }