Как обновить на UI таблицу

Я использую WPF в качестве UI для Windows приложения. Мне нужно отобразить на нем таблицу из SQL Server. Начал следующим образом. Использую Prism

class MainVM : BindableBase
{
    public MainVM()
    {
        currentTasks TaskList = new ObservableCollection<Task>(currentTasks.Tasks);            
    }
    public ObservableCollection<Task> TaskList { get; private set; }
}

public class CurrentTasks : BindableBase
{
    public CurrentTasks()
    {
        RefreshTasks();
        timer = new Timer(5000);
        timer.Elapsed += Timer_Elapsed;
        timer.Enabled = true;
    }

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        RefreshTasks();
    }

    private void RefreshTasks()
    {
        using (var db = new MyDatabase())
        {
            var query = from b in db.Tasks select b;
            foreach (Task task in query)
            {
                tasks.Add(task);
            }
            Tasks = new ReadOnlyObservableCollection<Task>(tasks);
        }
    }
    private ObservableCollection<Task> tasks = new ObservableCollection<Task>();
    public ReadOnlyObservableCollection<Task> Tasks { get; private set; }
    private Timer timer;
}

По таймеру я собираюсь обновлять таблицу. Как её обновить на UI? Может какие-нибудь подходы к таким задачам подскажите :)


Ответы (1 шт):

Автор решения: aepot

1) MainVM сделать как DataContext у окна

MainWindow.xaml

<Window.DataContext>
    <local:MainVM/>
</Window.DataContext>

При этом из кода конструктор MainVM вызывать не нужно, а если потребуется обратиться к существующему экземпляру из класса MainWindow, это можно сделать так:

MainVM vm = DataContext as MainVM;

2) Далее создать класс с данными, в которых будут храниться ячейки таблицы. К сожалению, я не работал с Entity или Prizm, поэтому вам решать, как у вас будет выглядеть класс с данными. Важно, что если вы хотите при любых програмных изменениях в данных, видеть их на экране, то он должен реализовывать INotifyPropertyChanged интерфейс, или наследовать BindableBase, как в вашем случае с использованием MVVM Light. Я сам MVVM Light не использую, поэтому этот ответ создан без учета его преимуществ.

К примеру, пусть данные содержат одно свойство строкового типа, тогда получится что-то вот такое:

DataItem.cs

public class DataItem : INotifyPropertyChanged
{
    private string _myValue;

    public string MyValue
    {
        get => _myValue;
        set { _myValue = value; OnPropertyChanged(nameof(MyValue)); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

3) В MainVM нужно добавить коллекцию с этим типом данных.

MainVM.cs

public class MainVM : INotifyPropertyChanged
{
    private ObservableCollection<DataItem> _gridData;
    public ObservableCollection<DataItem> GridData;
    {
        get => _gridData;
        set
        {
            _gridData = value;
            OnPropertyChanged(nameof(GridData));
        }
    }
    public MainVM()
    {
        // здесь можно проинициализировать коллекцию с данными, если требуется
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

4) Добавить DataGrid в UI.

MainWindow.xaml

<DataGrid ItemsSource="{Binding GridItems}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextBoxColumn Width="*" Binding="{Binding MyValue}" />
    </DataGrid.Columns>
</DataGrid>

Так как изменение ItemsSource автоматически меняет DataContext у таблицы, то {Binding MyValue} уже идет относительно коллекции, а не относительно окна

→ Ссылка