Search code examples
c#wpfxamlmvvmdatagrid

How to update datagrid xaml MVVM style


I am very new to this MVVM idea, was trying to write my first MVVM application to get my feet wet. Got a little bit of progress but hit road block as I progress. My question is a very basic fundamental one that could be easily addressed with code behind, but it was discouraged to do so as it violates the loose coupling principal I guess. So this is the problem I have:

My Model:

public class ToDoItemModel
{
    private DateTime    _TodoDate;
    private string      _TodoDescription;
    private TimeSpan    _TodoTimeSpan;
    private string      _StartTime;

    public string StartTime
    {
        get { return _StartTime; }
        set
        {
            _StartTime = value;
        }
    }
    public TimeSpan ToDoTimeSpan
    {
        get { return _TodoTimeSpan; }
        set
        {
            _TodoTimeSpan = value;
        }
    }        
    public string ToDoDescription
    {
        get { return _TodoDescription; }
        set
        {
            _TodoDescription = value;
        }
    }      
    public DateTime ToDoDate
    {
        get { return _TodoDate; }
        set
        {
            _TodoDate = value;
        }
    }

    public override string ToString()
    {
        return string.Format("Date: {0}- Time: {1}- Duration: {2}- Description: {3}",_TodoDate.ToString("d"),_StartTime,_TodoTimeSpan,_TodoDescription);
    }
}

My viewModel:

    public class ToDoListModelView:INotifyPropertyChanged
    {
        List<ToDoItemModel> _myModel = new List<ToDoItemModel>();
        public ICommand AddToDo
        {
            get
            {
                return new RelayCommand(addToDo);
            }
        }
        public ToDoListModelView()
        {
            _myModel.Add(new ToDoItemModel() { ToDoDate = DateTime.Now, ToDoDescription = "Testing 1" });
            _myModel.Add(new ToDoItemModel() { ToDoDate = DateTime.Now.AddDays(1), ToDoDescription = "Testing 2" });
        }
        public List<ToDoItemModel> myModel 
        { 
            get { return _myModel; } 
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var handler = this.PropertyChanged;
            if (handler!=null)
            {
                handler(this, e);
            }
        }
        public void RaisePropertyChanged(string PropertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(PropertyName));
        }

        private void addToDo()
        {
            _myModel.Add(new ToDoItemModel() { ToDoDate = DateTime.Now.AddDays(2), ToDoDescription = "From Relay Command" });
RaisePropertyChanged("DataGridChanged");
        }
    }

The viewModel implements INotifyPropertyChanged, and use a class RelayCommand that implements ICommand interface.

My view is:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestWPF" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="TestWPF.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="1,0,-1,0" d:DataContext="{d:DesignData /SampleData/ToDoListModelSampleData.xaml}">
        <Button x:Name="AddToDoButton" Content="Add Todo Item&#xA;" 
                  HorizontalAlignment="Left" Margin="419,90,0,0" VerticalAlignment="Top" Width="78" Height="33.04"
                  Command="{Binding AddToDo}"/>
        <DataGrid x:Name="TodoList" HorizontalAlignment="Left" 
                  Margin="33,184,0,0" VerticalAlignment="Top" 
                  RenderTransformOrigin="-0.833,-0.846" Height="108" Width="464" 
                  ItemsSource="{Binding myModel}" 
                  Style="{DynamicResource ToDoEntry}"/>
    </Grid>
</Window>

When I hit F5 the application ran and the 2 initial records were displayed. enter image description here

However, when I hit the button add, I saw the new record was added internally but the datagrid was not updated. I know the datagrid needs to be refreshed somehow, but I am not sure how to tell the grid to refresh the way MVVM is supposed to handle. My current code behind is as simple as that:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ToDoListModelView();
    }
}

According to the documentation I read from Microsoft site and if I understand it correctly, RaisePropertyChange is supposed to flag a change event occurs, I am just confused how to tie the event to refresh the grid using xaml without any code behind. Please help.


Solution

  • Change your List<ToDoItemModel> to an ObservableCollection<ToDoItemModel>

    A List<T> does not notify the UI to update when an item gets added or removed from the collection, while an ObservableCollection<T> does.