Самый просто вариант обновлять данные перезаписью DataTable.
myGrid.ItemsSource = null;
myGrid.ItemsSource = myDataSource;
Можно так же изменять напрямую у DataGrid его колонки из кода, а сами данные связывать через ObservableCollection.
myGrid.Columns.Clear();
foreach(var header in Headers)
{
myGrid.Columns.Add(new DataGridTextColumn()
{
Header = header.DisplayName,
Binding = new Binding(header.BindingName)
})
}
Можно заморочиться и кастомизировать DataGrid, чтобы работать только из VM с коллекциями и разорвать связь с View. Но я не уверен, что этот подход будет хорошим, мне просто было интересно попробовать и код можно еще долго улучшать.
Header
public class Header
{
public string DisplayName { get; set; }
public string BindingName { get; set; }
}
CustomDataGrid
public class CustomDataGrid : DataGrid
{
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(
"Columns",
typeof(ObservableCollection<Header>),
typeof(CustomDataGrid),
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(ColumnsPropertyCallback)));
public new ObservableCollection<Header> Columns
{
get { return (ObservableCollection<Header>)GetValue(ColumnsProperty); }
set {
SetValue(ColumnsProperty, value);
}
}
private static void ColumnsPropertyCallback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
var customDataGrid = dp as CustomDataGrid;
if (e.OldValue != null)
{
customDataGrid.Columns.CollectionChanged -= customDataGrid.CustomColumns_CollectionChanged;
}
if (e.NewValue != null)
{
customDataGrid.Columns.CollectionChanged += customDataGrid.CustomColumns_CollectionChanged;
}
customDataGrid.Refresh();
}
private void CustomColumns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Refresh();
}
private void Refresh()
{
base.Columns.Clear();
if (this.Columns != null)
this.Columns.ToList().ForEach(header => base.Columns.Add(new DataGridTextColumn() { Header = header.DisplayName, Binding = new Binding(header.BindingName) }));
}
}
ViewModel класс с примером
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Header> customColumns = new ObservableCollection<Header>();
public ObservableCollection<Header> CustomColumns
{
get { return customColumns; }
set
{
customColumns = value;
OnPropertyChanged();
}
}
private ObservableCollection<object> customData = new ObservableCollection<object>();
public ObservableCollection<object> CustomData
{
get { return customData; }
set
{
customData = value;
OnPropertyChanged();
}
}
private int counter = 1;
private ICommand _btnClick;
public ICommand BtnClick
{
get
{
if (_btnClick == null)
{
_btnClick = new RelayCommand(
p => true,
p =>
{
CustomColumns.Clear();
CustomData.Clear();
dynamic v = null;
if (counter % 2 == 0)
{
CustomColumns.Add(new Header() { DisplayName = "ID", BindingName = "ID" });
CustomColumns.Add(new Header() { DisplayName = "Имя", BindingName = "Name" }) ;
CustomColumns.Add(new Header() { DisplayName = "Фамилия", BindingName = "Surname" });
for (int i = 0; i < counter; i++)
{
v = new { ID = i, Name = "Имя " + i, Surname = "Фамилия " + i };
CustomData.Add(v);
}
}
else
{
CustomColumns.Add(new Header() { DisplayName = "ID", BindingName = "ID" });
CustomColumns.Add(new Header() { DisplayName = "Кол-во товара", BindingName = "Amount" });
CustomColumns.Add(new Header() { DisplayName = "Цена", BindingName = "Price" });
CustomColumns.Add(new Header() { DisplayName = "Описание", BindingName = "Description" });
CustomColumns.Add(new Header() { DisplayName = "Поставщик", BindingName = "Retailer" });
for (int i = 0; i < counter; i++)
{
v = new { ID = i, Amount = i + i, Price = i + "$", Description = "Описание", Retailer = "Поставщик " + i };
CustomData.Add(v);
}
}
counter++;
});
}
return _btnClick;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding BtnClick}">Start</Button>
</StackPanel>
<local:CustomDataGrid Grid.Row="1" Columns="{Binding CustomColumns}" ItemsSource="{Binding CustomData}" AutoGenerateColumns="False" x:Name="xGrid"></local:CustomDataGrid>
</Grid>
</Window>
Код View тогда получается пустой
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
Код RelayCommand на всякий случай тоже прилагаю
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}

myGrid.ItemsSource = null;и потомmyGrid.ItemsSource = myDataSource;. Но лучше перейти с DataTable на что-то более подходящее. – Alex Krass Jan 05 '22 at 12:16