DataGrid删除列以后,需要先清空ItemsSouce,再重新绑定数据源,在MVVM模式下面,如果直接把控件通过CommandParameter传到ViewModel进行修改,就显得很别扭
想了很久,才想到这个方法,如果大佬们有更好的方法,也可以指导下。
首先准备一个命令类
1 public class RelayCommand : ICommand 2 { 3 private Action<Action<string>> _addColumn; 4 5 public RelayCommand(Action<Action<string>> addColumn) 6 { 7 _addColumn = addColumn; 8 } 9 10 public event EventHandler CanExecuteChanged; 11 12 public bool CanExecute(object parameter) 13 { 14 return true; 15 } 16 17 public void Execute(object parameter) 18 { 19 _addColumn?.Invoke(parameter as Action<string>); 20 } 21 }
然后准备一个转换器 关键就是这个 他会把添加列的执行方法传递给ViewModel
1 public class ColumnConverter : IValueConverter 2 { 3 private DataGrid _dataGrid; 4 5 public void AddColumn(string name) 6 { 7 //如果存在相同名称 就直接return 8 for (int i = 0; i < _dataGrid.Columns.Count; i++) 9 { 10 var col = _dataGrid.Columns[i]; 11 if (col.Header.ToString() == name) 12 { 13 return; 14 } 15 } 16 17 //添加列和绑定数据 18 _dataGrid.Columns.Add(new DataGridTextColumn() { Header = name, Binding = new Binding(name) }); 19 } 20 21 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 22 { 23 _dataGrid = value as DataGrid; 24 25 //把添加列的执行方法返回给ViewModel 26 return new Action<string>(AddColumn); 27 } 28 29 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 30 { 31 throw new NotImplementedException(); 32 } 33 }
再准备一个ViewModel类,验证逻辑就先省略了
1 public class MainViewModel : INotifyPropertyChanged 2 { 3 private string _columnName; 4 5 private DataTable _data; 6 7 public RelayCommand AddColumnCmd { get; set; } 8 9 public DataTable Data 10 { 11 get => _data; 12 set => _data = value; 13 } 14 15 public RelayCommand DelColumnCmd { get; set; } 16 17 public MainViewModel() 18 { 19 //初始化数据 20 InitialData(); 21 22 //初始化命令 23 AddColumnCmd = new RelayCommand(AddColumn); 24 DelColumnCmd = new RelayCommand(DelColumn); 25 } 26 27 public string Name 28 { 29 get { return _columnName; } 30 set { _columnName = value; OnPropertyChanged(); } 31 } 32 33 public event PropertyChangedEventHandler PropertyChanged; 34 35 private void AddColumn(Action<string> action) 36 { 37 action?.Invoke(Name); 38 Data.Columns.Add(new DataColumn() { ColumnName = Name }); 39 } 40 41 private void DelColumn(Action<string> action) 42 { 43 action?.Invoke(Name); 44 45 Data.Columns.Remove(Name); 46 } 47 48 /// <summary> 49 /// 初始化数据 50 /// </summary> 51 private void InitialData() 52 { 53 Data = new DataTable(); 54 for (int i = 0; i < 5; i++) 55 { 56 var col = new DataColumn() { ColumnName = (i + 1).ToString().PadLeft(2, '0') }; 57 Data.Columns.Add(col); 58 } 59 60 for (int i = 0; i < 10; i++) 61 { 62 var row = Data.NewRow(); 63 for (int j = 0; j < Data.Columns.Count; j++) 64 { 65 row[j] = i * j; 66 } 67 Data.Rows.Add(row); 68 } 69 } 70 71 private void OnPropertyChanged([CallerMemberName] string name = null) 72 { 73 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 74 } 75 }
然后是界面 ,绑定各种数据
1 <Window 2 x:Class="DataGrid动态添加列.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:DataGrid动态添加列" 7 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 8 Title="MainWindow" 9 Width="800" 10 Height="450" 11 mc:Ignorable="d"> 12 <Window.DataContext> 13 <local:MainViewModel /> 14 </Window.DataContext> 15 <Window.Resources> 16 <local:ColumnConverter x:Key="Converter" /> 17 </Window.Resources> 18 <Grid> 19 <StackPanel Orientation="Vertical"> 20 <TextBox Height="30" Text="{Binding Name}" /> 21 <Button 22 Command="{Binding AddColumnCmd}" 23 CommandParameter="{Binding ElementName=grid, Converter={StaticResource Converter}}" 24 Content="添加列" /> 25 <DataGrid x:Name="grid" ItemsSource="{Binding Data}" /> 26 </StackPanel> 27 </Grid> 28 </Window>
最终效果