Search code examples
c#wpfbindingmvvm-lightobservablecollection

ItemsControl does not update when ObservableCollection changes


I am creating a calendar and I am using MVVM light. When i change the observable Collection the UI is not updated. My goal is if i click on a button in my ItemsControl the observable Collection changes and should trigger the DataTriger in my buttonstyle.

Things from MainWindow:

private ObservableCollection<Dates> _list;
public ObservableCollection<Dates> List
        {
            get { return _list; }
            set
            {
                _list = value;
                RaisePropertyChanged(nameof(List));
            }
        }

public RelayCommand<DateTime> DayClickedCommand { get; private set; }
private void DayClickedeCommandParameterhandling(DateTime s)
        {
            for (int i = 0; i < List.Count; i++)
            {
                if (List[i].Date == s)
                {
                    List[i].IsSelected = true;
                }
            }
        }

Dates class:

public class Dates
    {
        public Dates(DateTime day, int currentMonth)
        {
            Date = day;
            Day = day.Day.ToString();
            if ((int)day.Month == currentMonth)
            {
                IsInactive = false;
            }
            else
            {
                IsInactive = true;
            }
            if (day.DayOfYear == DateTime.Today.DayOfYear)
            {
                IsToday = true;
            }
            else IsToday = false;
        }

        #region Properties
        public DateTime Date { get; set; }
        public string Day { get; set; }
        public bool IsInactive { get; set; }
        public bool IsToday { get; set; }
        public bool IsSelected { get; set; }


        #endregion Properties
    }

My Xaml:

 <ItemsControl ItemsSource="{Binding List}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <WrapPanel></WrapPanel>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate >
                                <Grid Height="{Binding ElementName=Monday, Path=ActualHeight}" Width="{Binding ElementName=Monday, Path=ActualWidth}" Name="grid">
                                    <Button  Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.DayClickedCommand}" CommandParameter="{Binding Date}"  VerticalContentAlignment="Center" HorizontalContentAlignment="Center" MinHeight="10" MinWidth="10" FontSize="{Binding ElementName=textblockMonday, Path=FontSize}" Name="Button" BorderThickness="3" Content="{Binding Day}" >
                                            <Button.Style>
                                            <Style TargetType="Button">
                                                <Style.Triggers>
                                                    <DataTrigger Binding="{Binding IsInactive}" Value="True">
                                                        <Setter Property="Foreground" Value="Green" />
                                                        <Setter Property="Background" Value="Transparent" />
                                                    </DataTrigger> 
                                                    <DataTrigger Binding="{Binding IsInactive}" Value="false">
                                                        <Setter Property="Background" Value="Transparent" />
                                                    </DataTrigger>
                                                    <DataTrigger Binding="{Binding IsToday}" Value="true">
                                                        <Setter Property="Background" Value="Yellow" />
                                                        <Setter Property="Foreground" Value="Orange" />
                                                        <Setter Property="BorderBrush" Value="Orange" />
                                                    </DataTrigger> 
                                                    <DataTrigger Binding="{Binding IsToday}" Value="false">
                                                        <Setter Property="BorderBrush" Value="Transparent" />
                                                    </DataTrigger>
                                                    <DataTrigger Binding="{Binding IsSelected}" Value="true">
                                                        <Setter Property="Background" Value="Green" />
                                                        <Setter Property="Foreground" Value="Purple" />
                                                        <Setter Property="BorderBrush" Value="Orange" />
                                                    </DataTrigger>
                                                </Style.Triggers>
                                                </Style>
                                        </Button.Style>
                                    </Button>
                                </Grid>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>

The command is working and the collection is changed, but the ui is not informed.


Solution

  • Your Dates class should implement INotifyPropertyChanged and raise the PropertyChanged event for the IsSelected property:

    public class Dates : INotifyPropertyChanged
    {
        public Dates(DateTime day, int currentMonth)
        {
            Date = day;
            Day = day.Day.ToString();
            if ((int)day.Month == currentMonth)
            {
                IsInactive = false;
            }
            else
            {
                IsInactive = true;
            }
            if (day.DayOfYear == DateTime.Today.DayOfYear)
            {
                IsToday = true;
            }
            else IsToday = false;
        }
    
        #region Properties
        public DateTime Date { get; set; }
        public string Day { get; set; }
        public bool IsInactive { get; set; }
        public bool IsToday { get; set; }
    
        private bool _isSelected;
        public bool IsSelected
        {
            get { return _isSelected; }
            set { _isSelected = value; NotifyPropertyChanged(); }
        }
        #endregion Properties
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName]
            string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    An ObservableCollection<T> doesn't raise change notifications when the T items in it are modified. It raises an event when you add or remove items to and from it only.