Realtime update of DataGrid C#

Viewed 158

I'm creating a UI that visualizes som parts of a simulator. I am supposed to present some of the values in a table format, however I'm unable to get the table to update continuously when its already initialized (it initialized with the correct values, but is then static when you look at it, so you have to go to another page and then back to get the table to update) This is the code:

<Page x:Class="SimulatorUI.RawDataPage"
      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" 
      xmlns:local="clr-namespace:SimulatorUI"
      mc:Ignorable="d" 
      d:DesignHeight="950" d:DesignWidth="750"
      Title="RawDataPage">

    <DataGrid Name="dataTable" MinWidth="500" Margin="10 10 10 10" HorizontalContentAlignment="Center" HorizontalAlignment="Center"/>
</Page>

And the c# code looks like this

    public partial class RawDataPage : Page
{
    List<TankModule> tankList;
    public RawDataPage(List<TankModule> list)
    {
        tankList = list;
        InitializeComponent();
        List<displayModule> data = loadTable();
        dataTable.ItemsSource = data;
        Task.Run(() => updateLoop());   
    }
    public List<displayModule> loadTable()
    {
        List<displayModule> modules = new List<displayModule>();
        foreach(TankModule tank in tankList)
        {
            modules.Add(new displayModule(tank));
        }
        return modules;
    }     
    internal async Task updateLoop()
    {
        for (; ; )
        {
            dataTable.ItemsSource = null;
            dataTable.ItemsSource = loadTable();
            await Task.Delay(1000);
        }
    }
}
1 Answers

Data binding works best in these cases.

Change the tankList from List to ObservableCollection to begin with, and bind the DataGrid to tankList. Now, whenever you will add or remove a new item in tankList, the DataGrid will update to reflect the change.

The code-behind should look like this:

// Add this using to use ObservableCollection
using System.Collections.ObjectModel;

public partial class RawDataPage : Page
{
    // I've renamed tankList to TankList, as it is a convention to name public properties in Pascal case
    public ObservableCollection<TankModule> TankList { get; set; }

    public RawDataPage(List<TankModule> list)
    {
        DataContext = this; // This will bind this instance as the data context of the view

        tankList = new ObservableCollection<TankModule>(list);
    }
}

In the View:

<Page x:Class="SimulatorUI.RawDataPage"
      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" 
      xmlns:local="clr-namespace:SimulatorUI"
      mc:Ignorable="d" 
      d:DesignHeight="950" d:DesignWidth="750"
      Title="RawDataPage">

    <DataGrid Name="dataTable" ItemsSource="{Binding TankList}" MinWidth="500" Margin="10 10 10 10" HorizontalContentAlignment="Center" HorizontalAlignment="Center"/>
</Page>

Note: if you modify an item in TankList, the view might not get updated. In that case, the TankModule class must implement INotifyPropertyChanged. You can also do something like this after modifying the list item to refresh the list:

ObservableCollection<TankModule> copy = TankList;
TankList = null;
TankList = copy;

Also, it is recommended to use a view model instead of doing all these in the code-behind.

Related