wpf -datagrid增刪改的自我進階過程(進階偏)

前言:在上一篇中,我們實現了datagrid的增刪改超小白版本。在這個進階版本中我會一個一個優化。(讓代碼看起來不那麼low,我真的是故意的,雖然low,但是沒那麼low啊)。MVVM是一個數據操作很方便的框架。WPF的數據綁定,前端框架vue。使用起來比以前的控件賦值、dom操作方便的多。廢話不多說,反正這個是你要掌握的技能點就OK了。
1、咱們先給自己定一個原則,頁面上所有的數據源都來自頁面本身的DataContext。咱們只准給頁面賦值一次DataContext;

   public MainWindow()
   {
       InitializeComponent();
       //初始化數據
       for(int i = 1; i <= 10; i++) {
           Students.Add(new Student()
           {
               ID = i,
               Name = Guid.NewGuid().ToString(),
               Sex = (EnumSex)(i%3)
           });
       }
       //頁面所有控件最開始的數據來源只有這一個
       DataContext = Students;
   }
   ///xaml代碼。
           <DataGrid ItemsSource="{Binding}" CanUserAddRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False"
                  CanUserDeleteRows="False" CanUserSortColumns="False" AutoGenerateColumns="True" SelectedCellsChanged="DGstudent_SelectedCellsChanged">
        </DataGrid>

2、修改編輯模塊,這塊功能是要綁定到Datagrid的選擇項,嗯,比上面的複雜點。但是也就是複雜一點點。

<!--Datagrid列表模塊刪除了SelectedCellsChanged事件,完全不需要了,是不是超方便-->
        <DataGrid ItemsSource="{Binding}" x:Name="DGstudent" CanUserAddRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False"
                  CanUserDeleteRows="False" CanUserSortColumns="False" AutoGenerateColumns="True" >
        </DataGrid>
        <!--修改模塊 datacontext綁定DGstudent的選中項是不是超簡單-->
        <WrapPanel DataContext="{Binding ElementName=DGstudent,Path=SelectedItem}">
            <Label>ID:</Label>
            <TextBox Width="100" IsReadOnly="True" x:Name='TbModifyID' Text="{Binding ID}"></TextBox>
            <Label>姓名:</Label>
            <TextBox Width="300" x:Name="TbModifyName" Text="{Binding Name}"></TextBox>
            <Label>性別:</Label>
            <ComboBox Width="100" x:Name="TbModifySex" Text="{Binding Sex}">
                <ComboBoxItem Content="未知" ></ComboBoxItem>
                <ComboBoxItem Content="男" ></ComboBoxItem>
                <ComboBoxItem Content="女" ></ComboBoxItem>
            </ComboBox>
            <Button Content="修改" x:Name="BtnModify" Click="BtnModify_Click"></Button>
            <Button Content="刪除" x:Name="BtnRemove" Click="BtnRemove_Click"></Button>
        </WrapPanel>

友情提示:大家可以一步一步運行看效果哦,這樣的話理解會身體一點。
3、完善修改功能。那就然都需要優化了,那肯定不能用事件一個一個改,這麼low的辦法;INotifyPropertyChanged。修改類如下

	//ID是不能被修改的,所以不需要通知。
    public class Student: INotifyPropertyChanged
    {
        public int ID { get; set; }

        private string _name { get; set; }
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                NotifyPropertyChanged();
            }
        }

        private EnumSex _sex { get; set; }


        public EnumSex Sex
        {
            get
            {
                return _sex;
            }
            set
            {
                _sex = value;
                NotifyPropertyChanged();
            }
        }

        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
///xaml  編輯按鈕已經不需要了,你會發現修改文本框的值的時候,表格就以及修改了。
        <WrapPanel DataContext="{Binding ElementName=DGstudent,Path=SelectedItem}">
            <Label>ID:</Label>
            <TextBox Width="100" IsReadOnly="True" x:Name='TbModifyID' Text="{Binding ID}"></TextBox>
            <Label>姓名:</Label>
            <TextBox Width="300" x:Name="TbModifyName" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}"></TextBox>
            <Label>性別:</Label>
            <ComboBox Width="100" x:Name="TbModifySex" Text="{Binding Sex,UpdateSourceTrigger=PropertyChanged}">
                <ComboBoxItem Content="未知" ></ComboBoxItem>
                <ComboBoxItem Content="男" ></ComboBoxItem>
                <ComboBoxItem Content="女" ></ComboBoxItem>
            </ComboBox>
            <!--<Button Content="修改" x:Name="BtnModify" Click="BtnModify_Click"></Button>-->
            <Button Content="刪除" x:Name="BtnRemove" Click="BtnRemove_Click"></Button>
        </WrapPanel>
        

4、刪除、新增。這個可必須要觸發事件的,怎麼辦呢,雖然現有已經支持,但是要改嘛,就要改的徹底點。那命令能不能也綁定呢,當然可以 ICommand瞭解下,親。

    public class AddCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            throw new NotImplementedException();
        }
    }

    public class RemoveCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            throw new NotImplementedException();
        }
    }

5、定義倆個命令,添加和刪除。繼承ICommand後。就發現問題了,誒?這個我怎麼操作頁面的數據集合Students呢?咱們可以把students放到全局變量裏面(還有其他方式,咱們先用最簡單的)。

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
           
            DataContext = GlobalViewModel.Students;
        }
    }

    public static class GlobalViewModel {

        public static List<Student> Students { get; set; } = new List<Student>();

        static GlobalViewModel() {
            //初始化數據
            for (int i = 1; i <= 10; i++)
            {
                Students.Add(new Student()
                {
                    ID = i,
                    Name = Guid.NewGuid().ToString(),
                    Sex = (EnumSex)(i % 3)
                });
            }
        }
    }

    public class AddCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            if (parameter is Student) {
                GlobalViewModel.Students.Add(parameter as Student);
            }
        }
    }

    public class RemoveCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            int.TryParse(parameter?.ToString(), out int id);
            var student = GlobalViewModel.Students.FirstOrDefault(x => x.ID == id);
            if (student !=null)
            {
                GlobalViewModel.Students.Remove(student);
            }
        }
    }

6、那強迫症的我們肯定表示DataContext = GlobalViewModel.Students;這個代碼能不能也在XAML頁面綁定呢。那肯定也是可以的(順帶把按鈕的命令也綁定上);

<Window x:Class="DataGridDemo.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:DataGridDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" DataContext="{Binding Source={x:Static local:GlobalViewModel.Students}}">
          <!--綁定全局靜態變量爲頁面數據源-->
    <StackPanel>
        <!--Datagrid列表模塊-->
        <DataGrid ItemsSource="{Binding}" x:Name="DGstudent" CanUserAddRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False"
                  CanUserDeleteRows="False" CanUserSortColumns="False" AutoGenerateColumns="True" >
        </DataGrid>
        <!--修改模塊-->
        <WrapPanel DataContext="{Binding ElementName=DGstudent,Path=SelectedItem}">
            <Label>ID:</Label>
            <TextBox Width="100" IsReadOnly="True" x:Name='TbModifyID' Text="{Binding ID}"></TextBox>
            <Label>姓名:</Label>
            <TextBox Width="300" x:Name="TbModifyName" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}"></TextBox>
            <Label>性別:</Label>
            <ComboBox Width="100" x:Name="TbModifySex" Text="{Binding Sex,UpdateSourceTrigger=PropertyChanged}">
                <ComboBoxItem Content="未知" ></ComboBoxItem>
                <ComboBoxItem Content="男" ></ComboBoxItem>
                <ComboBoxItem Content="女" ></ComboBoxItem>
            </ComboBox>
              <!--刪除按鈕綁定刪除命令-->
            <Button Content="刪除" x:Name="BtnRemove">
                <Button.Command>
                    <local:RemoveCommand></local:RemoveCommand>
                </Button.Command>
            </Button>
        </WrapPanel>
        <!--新增模塊-->
        <WrapPanel x:Name="WpAdd">
            <Label>姓名:</Label>
            <TextBox Width="300" x:Name="TbAddName"></TextBox>
            <Label>性別:</Label>
            <ComboBox Width="100" x:Name="TbAddSex">
                <ComboBoxItem Content="未知" ></ComboBoxItem>
                <ComboBoxItem Content="男" ></ComboBoxItem>
                <ComboBoxItem Content="女" ></ComboBoxItem>
            </ComboBox>
             <!--新增按鈕綁定新增命令-->
            <Button Content="新增">
                <Button.Command>
                    <local:AddCommand></local:AddCommand>
                </Button.Command>
            </Button>
        </WrapPanel>
    </StackPanel>
</Window>

7、上一步結束後我們運行,可以發現點擊按鈕後可以觸發事件了。但是因爲沒有設置參數,所以參數都是null的。刪除命令我們只需要帶上ID就行了,新增我們的話確實要帶上姓名和性別倆個參數。就需要藉助IMultiValueConverter了。

  <!--刪除按鈕  參數ID-->
            <Button Content="刪除" x:Name="BtnRemove" CommandParameter="{Binding ID}">
                <Button.Command>
                    <local:RemoveCommand></local:RemoveCommand>
                </Button.Command>
            </Button>

  <!--新增按鈕  多個參數,使用轉換器轉換爲對象-->
<Button Content="新增">
                <Button.CommandParameter>
                    <MultiBinding>
                        <MultiBinding.Converter >
                            <local:StudentConverter></local:StudentConverter>
                        </MultiBinding.Converter>
                        <Binding ElementName="TbAddName" Path="Text"></Binding>
                        <Binding ElementName="TbAddSex" Path="Text"></Binding>
                    </MultiBinding>
                </Button.CommandParameter>
                <Button.Command>
                    <local:AddCommand></local:AddCommand>
                </Button.Command>
            </Button>
///轉換器,姓名和性別構建一個Student新對象
    public class StudentConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            string name = values[0]?.ToString();
            if (Enum.TryParse(values[1]?.ToString(), out EnumSex sex) && !string.IsNullOrEmpty(name)) {
                return new Student()
                {
                    ID = GlobalViewModel.Students.Count + 1,
                    Name = name,
                    Sex = sex
                };
            }
            return null;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

8、新增和刪除功能調試時已經實現了,集合已經修改了。但是頁面並沒有發生改變。那是因爲我們的數組類型還是List。我們只需要修改爲:

        public static ObservableCollection<Student> Students { get; set; } = new ObservableCollection<Student>();

結語:增刪改已經差不多很完善了,當然還有許多可以優化的點。
https://download.csdn.net/download/qq_29198233/12062726

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章