WPF DataGrid与数据绑定

WPF DataGrid与数据绑定

MVVM基础

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Melphi.Mvvm.Base
{
    /// <summary>
    /// ViewModel模型基类(属性更改通知)
    /// A base class for objects of which the properties must be observable.
    /// </summary>
    public class ViewModelBase : INotifyPropertyChanged
    {

        public ViewModelBase() { }

        /// <summary>
        /// 当任何子属性更改其值时激发的事件
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };

        /// <summary>
        /// 调用此函数以触发 <see cref="PropertyChanged"/> 事件
        /// </summary>
        /// <param name="name"></param>
        //public void RaisePropertyChanged(string name)
        //{
        //    PropertyChanged(this, new PropertyChangedEventArgs(name));
        //}

        /// <summary>
        /// 调用此函数以触发 <see cref="PropertyChanged"/> 事件
        /// </summary>
        /// <param name="propertyName">(optional) The name of the property that changed.</param>
        public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }


        /// <summary>
        /// 更新属性,如果属性值没有发生变化,则不进行通知
        /// </summary>
        /// <typeparam name="T">属性类型【The type of the property that changed.】</typeparam>
        /// <param name="field">返回的属性值【The field storing the property's value.】</param>
        /// <param name="newValue">新的属性值【The property's value after the change occurred.】</param>
        /// <param name="properName">属性名【(optional) The name of the property that changed.】</param>
        protected void RaisePropertyChanged<T>(ref T field, T newValue, [CallerMemberName] string properName = null)
        {
            if (object.Equals(field, newValue))
                return;
            field = newValue;
            RaisePropertyChanged(properName);
        }

    }
}

using System;
using System.Windows.Input;

namespace Melphi.Mvvm.Base
{

    // 言论:
    //     If you are using this class in WPF4.5 or above, you need to use the GalaSoft.MvvmLight.CommandWpf
    //     namespace (instead of GalaSoft.MvvmLight.Command). This will enable (or restore)
    //     the CommandManager class which handles automatic enabling/disabling of controls
    //     based on the CanExecute delegate.

    /// <summary>
    ///  A generic command whose sole purpose is to relay its functionality to other objects
    ///  by invoking delegates. The default return value for the CanExecute method is
    ///  'true'. This class allows you to accept command parameters in the Execute and
    ///  CanExecute callback methods.
    /// </summary>
    /// <typeparam name="T">The type of the command parameter.</typeparam>
    public class RelayCommand<T> : ICommand
    {
        /// <summary>
        /// The execution logic. 
        /// </summary>
        private Action<T> mExecute;

        /// <summary>
        /// The execution status logic. 
        /// </summary>
        private Func<T, bool> mCanExecute;

        /// <summary>
        /// Initializes a new instance of the RelayCommand class that can always execute.
        /// 
        /// Exception:
        ///     T:System.ArgumentNullException:
        ///         If the execute argument is null.
        /// </summary>
        /// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure, you must set keepTargetAlive to true to avoid side effects.</param>
        /// <param name="keepTargetAlive">If true, the target of the Action will be kept as a hard reference, which might cause a memory leak. You should only set this parameter to true if the action is causing a closure. See http://galasoft.ch/s/mvvmweakaction.</param>
        public RelayCommand(Action<T> execute, bool keepTargetAlive = false)
        {
            // TODO: Check the T Type

            this.mExecute = execute;
        }

        /// <summary>
        /// Initializes a new instance of the RelayCommand class.
        /// 
        /// Exception:
        ///     T:System.ArgumentNullException:
        ///         If the execute argument is null.
        /// </summary>
        /// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure, you must set keepTargetAlive to true to avoid side effects.</param>
        /// <param name="canExecute">The execution status logic. IMPORTANT: If the func causes a closure, you must set keepTargetAlive to true to avoid side effects.</param>
        /// <param name="keepTargetAlive">If true, the target of the Action will be kept as a hard reference, which might cause a memory leak. You should only set this parameter to true if the action is causing a closure.</param>
        public RelayCommand(Action<T> execute, Func<T, bool> canExecute, bool keepTargetAlive = false)
        {
            // TODO: Check the T Type 

            this.mExecute = execute;
            this.mCanExecute = canExecute;
        }


        /// <summary>
        ///  Occurs when changes occur that affect whether the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged = (sender, e) => { };

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        /// <param name="parameter">Data used by the command. If the command does not require data to be passed,this object can be set to a null reference</param>
        /// <returns>true if this command can be executed; otherwise, false.</returns>
        public bool CanExecute(object parameter)
        {
            if (mCanExecute != null)
                return mCanExecute.Invoke((T)parameter);
            else
                return true;
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">Data used by the command. If the command does not require data to be passed,this object can be set to a null reference</param>
        public virtual void Execute(object parameter)
        {
            mExecute.Invoke((T)parameter);
        }

        /// <summary>
        /// Raises the CanExecuteChanged event.
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged(this, null);
        }
    }



    // 言论:
    //     If you are using this class in WPF4.5 or above, you need to use the GalaSoft.MvvmLight.CommandWpf
    //     namespace (instead of GalaSoft.MvvmLight.Command). This will enable (or restore)
    //     the CommandManager class which handles automatic enabling/disabling of controls
    //     based on the CanExecute delegate.

    /// <summary>
    /// A command whose sole purpose is to relay its functionality to other objects by invoking delegates. The default return value for the CanExecute method is 'true'.This class does not allow you to accept command parameters in the Execute and CanExecute callback methods.
    /// </summary>
    public class RelayCommand : ICommand
    {

        /// <summary>
        /// The execution logic. 
        /// </summary>
        private Action mExecute;

        /// <summary>
        /// The execution status logic. 
        /// </summary>
        private Func<bool> mCanExecute;

        /// <summary>
        /// Initializes a new instance of the RelayCommand class that can always execute.
        /// 
        /// Exception:
        ///     T:System.ArgumentNullException:
        ///         If the execute argument is null.
        /// </summary>
        /// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure, you must set keepTargetAlive to true to avoid side effects.</param>
        /// <param name="keepTargetAlive">If true, the target of the Action will be kept as a hard reference, which might cause a memory leak. You should only set this parameter to true if the action is causing a closure.</param>
        public RelayCommand(Action execute, bool keepTargetAlive = false)
        {
            this.mExecute = execute;
        }

        /// <summary>
        /// Initializes a new instance of the RelayCommand class.
        /// 
        /// Exception:
        ///     T:System.ArgumentNullException:
        ///         If the execute argument is null.
        /// </summary>
        /// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure, you must set keepTargetAlive to true to avoid side effects.</param>
        /// <param name="canExecute">The execution status logic. IMPORTANT: If the func causes a closure, you must set keepTargetAlive to true to avoid side effects.</param>
        /// <param name="keepTargetAlive">If true, the target of the Action will be kept as a hard reference, which might cause a memory leak. You should only set this parameter to true if the action is causing a closures.</param>
        public RelayCommand(Action execute, Func<bool> canExecute, bool keepTargetAlive = false)
        {
            this.mExecute = execute;
            this.mCanExecute = canExecute;
        }

        /// <summary>
        /// Occurs when changes occur that affect whether the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged = (sender, e) => { };


        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        /// <param name="parameter">This parameter will always be ignored.</param>
        /// <returns>true if this command can be executed; otherwise, false.</returns>
        public bool CanExecute(object parameter)
        {
            if (mCanExecute != null)
                return this.mCanExecute.Invoke();
            else
                return true;
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">This parameter will always be ignored.</param>
        public virtual void Execute(object parameter)
        {
            this.mExecute.Invoke();
        }

        /// <summary>
        /// Raises the GalaSoft.MvvmLight.Command.RelayCommand.CanExecuteChanged event.
        /// </summary>
        public void RaiseCanExecuteChanged()
        {

        }
    }

}

My Model

   public class Student : ViewModelBase
    {
        private int id;

        public int Id
        {
            get { return id; }
            set { id = value; RaisePropertyChanged(); }
        }

        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; RaisePropertyChanged(); }
        }
    }

My ViewModel


    public class DataGridViewModel : ViewModelBase
    {
        private readonly LocalDb mLocalDb;

        public DataGridViewModel()
        {
            mLocalDb = new LocalDb();
            QueryCommand = new RelayCommand(Query);

            ResetCommand = new RelayCommand(() =>
            {
                SearchText = string.Empty;
                Query();
            });

            EditCommand = new RelayCommand<int>(t => Edit(t));

            DeleteCommand = new RelayCommand<int>(t => Delete(t));

            AddCommand = new RelayCommand(Add);
            Query();
        }

        private ObservableCollection<Student> students;

        public ObservableCollection<Student> Students
        {
            get { return students; }
            set { students = value; RaisePropertyChanged(); }
        }

        private string searchText = string.Empty;

        public string SearchText
        {
            get { return searchText; }
            set { searchText = value; RaisePropertyChanged(); }
        }

        public RelayCommand QueryCommand { get; set; }

        public RelayCommand ResetCommand { get; set; }

        public RelayCommand<int> EditCommand { get; set; }

        public RelayCommand<int> DeleteCommand { get; set; }

        public RelayCommand AddCommand { get; set; }

        /// <summary>
        /// Query
        /// </summary>
        private void Query()
        {
            var models = mLocalDb.GetStudentsByName(SearchText);
            Students = new ObservableCollection<Student>();
            if (models != null)
            {
                models.ForEach(arg =>
                {
                    Students.Add(arg);
                });
            }
        }

        private void Edit(int id)
        {
            var model = mLocalDb.GetStudentsById(id);
            if (model != null)
            {
                UserWindow window = new UserWindow(model);
                var r = window.ShowDialog();
                if (r.Value)
                {
                    var stu = Students.FirstOrDefault(t => t.Id == id);
                    if (stu != null)
                    {
                        stu.Name = model.Name;
                    }
                }
            }
        }

        private void Delete(int id)
        {
            var model = mLocalDb.GetStudentsById(id);
            if (model != null)
            {
                var r = MessageBox.Show($"确认删除当前学生信息{model.Name}?", "操作提示", MessageBoxButton.OK, MessageBoxImage.Question);
                if (r == MessageBoxResult.OK)
                {
                    mLocalDb.DeleteStudent(id);
                    this.Query();
                }

            }

        }

        private void Add()
        {
            Student student = new Student();
            UserWindow window = new UserWindow(student);
            var r = window.ShowDialog();
            if (r.Value)
            {
                student.Id = Students.Max(t => t.Id) + 1;
                mLocalDb.AddStudent(student);
                this.Query();
            }

        }
    }

My View

<UserControl x:Class="Deamon.View.PERSONALIZATION.DataGridUsage.DataGridView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Deamon.View.PERSONALIZATION.DataGridUsage"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="60"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Search" VerticalAlignment="Center"/>
            <TextBox Width="200" Text="{Binding SearchText}" Height="25"/>
            <Button Width="70" Command="{Binding QueryCommand}" Height="25" Content="Find" Margin="10 0 0 0"/>
            <Button Width="70" Command="{Binding ResetCommand}" Height="25" Content="Reset" Margin="10 0 0 0"/>
            <Button Width="70" Command="{Binding AddCommand}" Height="25" Content="Add" Margin="10 0 0 0"/>
        </StackPanel>

        <DataGrid Grid.Row="1" ColumnWidth="*" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding Students}">
            <DataGrid.Columns>
                <DataGridTextColumn IsReadOnly="True" Header="编号" Binding="{Binding Id}"/>
                <DataGridTextColumn IsReadOnly="True" Header="姓名" Binding="{Binding Name}"/>
                <DataGridTemplateColumn Header="操作">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Button Width="60" Height="25" Content="Modify" 
                                        CommandParameter="{Binding Id}"
                                        Command="{Binding DataContext.EditCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=DataGrid}}"
                                        Background="White" Foreground="Black"/>
                                <Button Width="60" Height="25" Content="Delete" 
                                        CommandParameter="{Binding Id}"
                                        Command="{Binding DataContext.DeleteCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=DataGrid}}"
                                         Background="Red" Foreground="White"/>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

    </Grid>
</UserControl>

    /// <summary>
    /// DataGridView.xaml 的交互逻辑
    /// </summary>
    public partial class DataGridView : UserControl
    {
        public DataGridView()
        {
            InitializeComponent();

            DataContext = new DataGridViewModel();
        }
    }
<Window x:Class="Deamon.View.PERSONALIZATION.DataGridUsage.UserWindow"
        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:Deamon.View.PERSONALIZATION.DataGridUsage"
        mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True" WindowStartupLocation="CenterScreen"
        Title="UserWindow" Height="350" Width="400">
    <Border Padding="2" Background="Transparent">
        <Grid Background="White">
            <Grid.Effect>
                <DropShadowEffect BlurRadius="20" ShadowDepth="2" Color="Red"/>
            </Grid.Effect>
            <Grid.RowDefinitions>
                <RowDefinition Height="60"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="60"/>
            </Grid.RowDefinitions>

            <TextBlock Text="编辑用户信息" FontWeight="Bold" FontSize="25" Margin="10 0 0 0" VerticalAlignment="Center"/>

            <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">

                <TextBlock Text="姓名:"/>
                <TextBox Width="200" Height="25" Text="{Binding Path=Model.Name,Mode=TwoWay}"/>

            </StackPanel>

            <StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Right">
                <Button Width="70" Height="25" Click="OK_Click" Content="确定"/>
                <Button Width="70" Height="25" Click="Cancel_Click" Content="取消" Margin="10 0 10 0"/>
            </StackPanel>
        </Grid>
    </Border>
   
</Window>

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Deamon.View.PERSONALIZATION.DataGridUsage
{
    /// <summary>
    /// UserWindow.xaml 的交互逻辑
    /// </summary>
    public partial class UserWindow : Window
    {
        public UserWindow(Student student)
        {
            InitializeComponent();

            this.DataContext = new
            {
                Model = student
            };
        }

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }

        private void OK_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;

        }
    }
}

My Service


    public class LocalDb
    {

        public LocalDb()
        {
            Init();
        }
        private void Init()
        {
            mStudents = new List<Student>();

            for (int i = 1; i < 30; i++)
            {
                mStudents.Add(new Student() { Id = i, Name = $"Melphi" + i });
            }
        }

        private List<Student> mStudents;

        public List<Student> GetStudents()
        {
            return mStudents;
        }


        public void AddStudent(Student student)
        {
            mStudents.Add(student);
        }

        public void DeleteStudent(int id)
        {
            var model = mStudents.FirstOrDefault(t => t.Id == id);

            if (model != null)
            {
                mStudents.Remove(model);
            }
        }

        public List<Student> GetStudentsByName(string name)
        {
            return mStudents.Where(q => q.Name.Contains(name)).ToList();
        }

        public Student GetStudentsById(int id)
        {
            var model = mStudents.FirstOrDefault(q => q.Id == id);
            if (model != null)
            {
                return new Student()
                {
                    Id = model.Id,
                    Name = model.Name
                };
            }
            else
                return null;
        }
    }

sds

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值