c# WPF вывод List и динамическое изменение
Объект :
public class MyTestObject
{
public class TestObject
{
public string first { get; set; }
public string second { get; set; }
}
}
У меня есть List<MyTestObject.TestObject>
Нужно вывести этот List объектов в две колонки по принципу
first1|second1
------|-------
first2|second2
------|-------
first3|second3
Как лучше это сделать? Длина листа меняется, точного значения нет.
Я примерно понимаю как можно это сделать костылём, но
Проблема в том, что мне нужно чтобы при изменении данных в этом List они тут же менялись в окне программы. Количество объектов в List при этом изменяться не будет.
Ответы (1 шт):
Если использовать паттерн MVVM, то это делается так. Для сообщения таблице об изменениях в ячейках используется событие PropertyChanged из интерфейса INotifyPropertyChanged.
Строка таблицы будет выглядеть так:
DataItem.cs
public class DataItem : INotifyPropertyChanged
{
private string _first;
private string _second;
public string First
{
get => _first; // то же самое, что { return _first; }
set
{
_first = value;
OnPropertyChanged(nameof(First));
}
}
public string Second
{
get => _second;
set
{
_second = value;
OnPropertyChanged(nameof(Second));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Далее, создаю MainViewModel класс, который будет выступать в роли датаконтекста для нашего окна. Это позволит нам легко и просто использовать биндинги.
MainViewModel так же реализует INotifyPropertyChanged, чтобы DataGrid могла сама узнать, если я переключу GridItems на другую коллекцию.
ObservableCollection это практически то же самое, что и List, только внутри этой коллекции срабатывает событие CollectionChanged, с помощью него таблица узнает, были ли добавлены или удалены элементы из коллекции.
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<DataItem> _gridItems;
public ObservableCollection<DataItem> GridItems
{
get => _gridItems;
set
{
_gridItems = value;
OnPropertyChanged(nameof(GridItems));
}
}
public MainViewModel()
{
// здесь можно добавить или загрузить элементы
GridItems = new ObservableCollection<DataItem>();
GridItems.Add(new DataItem() { First = "first value", Second = "second value" });
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Теперь самое главное, как все это подружить с интерфейсом.
- Добавить в
Window.DataContextнаш классMainViewModel - Привязать
DataGridк коллекцииGridItems - Привязать колонки таблицы к
FirstиSecond
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
Title="MainWindow" Height="300" Width="600">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}">
<DataGrid.Columns>
<DataGridTextColumn Header="First Column" Width="*" Binding="{Binding First}"/>
<DataGridTextColumn Header="Second Column" Width="*" Binding="{Binding Second}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
И на последок:
INotifyPropertyChangedнаходится в неймспейсеSystem.ComponentModelObservableCollection- вSystem.Collections.ObjectModel
Дополнительная прелесть этого подхода к реализации еще в том, что данные внесенные в интерфейсе сразу же попадут в данные GridItems и их можно будет использовать в коде без непосредственного обращения к DataGrid.