1. 程式人生 > 其它 >WPF MVVM模式下DataGrid動態增加列與刪除列

WPF MVVM模式下DataGrid動態增加列與刪除列

DataGrid刪除或者列以後,需要先清空DataGrid的ItemsSouce,再重新給DataGrid繫結資料來源,

直接在ViewModel裡面對資料來源進行新增和刪除,不會反應到介面上,

在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>

最終效果