Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView not updating after ObservableCollection is changed

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;
    }
like image 446
sachin saner Avatar asked Nov 20 '11 21:11

sachin saner


2 Answers

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;
}
like image 97
BFree Avatar answered Oct 21 '22 05:10

BFree


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.

like image 42
H.B. Avatar answered Oct 21 '22 07:10

H.B.