C# WPF数据绑定方法以及重写数据模板后数据绑定

2023-04-17 15:25:14 来源:博客园

写在前面

本文将会介绍WPF如何实现前后端数据绑定和在进行数据绑定时常用的方法和类以及对于DataGrid、ListView这样的控件重写数据模板后控件如何进行数据绑定


(相关资料图)

本文主要针对于数据绑定的基础实现进行介绍,通过此博文你将会有能力编写一个MVVM设计模式的C#、WPF项目。如果您是C#及WPF的资深开发人员本文可能对您没有太大的帮助,但如果你是一个正在学习和了解C#、WPF的开发人员来说本文可以帮助你认识MVVM设计模式和数据绑定。

一、实现前后端数据绑定:

说到前后端的数据绑定,就需要先说一下WPF的MVVM设计模式,它是由传统的MVC设计模式改进而来,不同点在于MVVM数据源更新不需要一个Controller控制器来向前台同步数据,同时前台数据更改也不需要控制器向后台同步。如果想深入详细的了解MVVM设计模式百度百科对这部分的讲解和说明我认为非常的详细和系统。也可以阅读下方的实例,相信通过代码实例更能够让你对MVVM有一个更深入的认识。

实例:

源代码地址(码云):https://gitee.com/hkb1202/csharp-wpf-data-binding-demo

实例基于.Net Core 3.1平台,为博主编写并亲测可用的,通过实例相信你可以更好的理解这部分内容。

新建一个WPF项目,并且添加Command类和MainWindowsViewModel类

Command.cs代码:

1 using System; 2 using System.Windows.Input; 3  4 namespace WpfExample 5 { 6     public class Command : ICommand 7     { 8  9         /// 10         /// 检查命令是否可以执行的事件,在UI事件发生导致控件状态或数据发生变化时触发11         /// 12         public event EventHandler CanExecuteChanged13         {14             add15             {16                 if (_canExecute != null)17                 {18                     CommandManager.RequerySuggested += value;19                 }20             }21             remove22             {23                 if (_canExecute != null)24                 {25                     CommandManager.RequerySuggested -= value;26                 }27             }28         }29 30         /// 31         /// 判断命令是否可以执行的方法32         /// 33         private Func _canExecute;34 35         /// 36         /// 命令需要执行的方法37         /// 38         private Action _execute;39 40         /// 41         /// 创建一个命令42         /// 43         /// 命令要执行的方法44         public Command(Action execute) : this(execute, null)45         {46 47         }48 49         /// 50         /// 创建一个命令51         /// 52         /// 命令要执行的方法53         /// 判断命令是否能够执行的方法54         public Command(Action execute, Func canExecute)55         {56             _execute = execute;57             _canExecute = canExecute;58         }59 60         /// 61         /// 判断命令是否可以执行62         /// 63         /// 命令传入的参数64         /// 是否可以执行65         public bool CanExecute(object parameter)66         {67             if (_canExecute == null) return true;68             return _canExecute(parameter);69         }70 71         /// 72         /// 执行命令73         /// 74         /// 75         public void Execute(object parameter)76         {77             if (_execute != null && CanExecute(parameter))78             {79                 _execute(parameter);80             }81         }82     }83 }Command.cs

Command类是实现ICommand接口,从而实现将前台的命令注册到后台的ViewModel中,在此不详细展开讲解,请先照抄代码,如果对这部分感兴趣可以查阅博客园中关于ICommand接口的详解。暂时不理解这里并不影响后续的编码。

MainWindowViewModel.cs代码:

1 using System.Collections.ObjectModel;  2 using System.ComponentModel;  3 using System.Windows;  4 using System.Windows.Controls;  5   6 namespace WpfExample  7 {  8     public class MainWindowViewModel : INotifyPropertyChanged  9     { 10         //实现接口当数据源变动通知前台UI 11         public event PropertyChangedEventHandler? PropertyChanged; 12  13         public void RaisePropertyChanged(string propName) 14         { 15             if (PropertyChanged != null) 16             { 17                 PropertyChanged(this, new PropertyChangedEventArgs(propName)); 18             } 19         } 20  21         ///  22         /// 前台DataGrid绑定的People集合 23         ///  24         public ObservableCollection People { get; set; } 25  26         ///  27         /// 绑定前台DataGrid控件SelectedItem字段上,用于保存当前选中的Item所对应的数据源 28         ///  29         public Person SelectItem 30         { 31             get 32             { 33                 return m_SelectItem; 34             } 35             set 36             { 37                 m_SelectItem = value; 38                 RaisePropertyChanged("SelectItem"); 39             } 40         } 41  42         ///  43         /// DataGrid控件中删除按钮命令 44         ///  45         public Command DelClick 46         { 47             get 48             { 49                 if (m_DelClick == null) 50                     m_DelClick = new Command(DeleteEvent); 51  52                 return m_DelClick; 53             } 54         } 55  56         ///  57         /// 前台添加小刚按钮命令 58         ///  59         public Command AddClick 60         { 61             get 62             { 63                 if (m_AddClick == null) 64                     m_AddClick = new Command(AdditionEvent); 65  66                 return m_AddClick; 67             } 68         } 69  70         ///  71         /// 前台修改Text按钮命令 72         ///  73         public Command ReviseClick 74         { 75             get 76             { 77                 if (m_ReviseClick == null) 78                     m_ReviseClick = new Command(ReviseEvent); 79  80                 return m_ReviseClick; 81             } 82         } 83  84         ///  85         /// 前台TextBlock控件显示的文本 86         ///  87         public string TextInfo 88         { 89             get 90             { 91                 return m_TextInfo; 92             } 93             set 94             { 95                 m_TextInfo = value; 96                 //数据源更新调用更新前台UI方法 97                 RaisePropertyChanged("TextInfo"); 98             } 99         }100 101         /// 102         /// DataGrid控件电话信息的TextBox键盘按下回车命令103         /// 104         public Command PressEnterKey105         {106             get107             {108                 if (m_PressEnterKey == null)109                     m_PressEnterKey = new Command(PressEnterKeyEvent);110 111                 return m_PressEnterKey;112             }113         }114 115         private Person m_SelectItem;116         private Command m_DelClick;117         private Command m_AddClick;118         private Command m_ReviseClick;119         private string m_TextInfo;120         private Command m_PressEnterKey;121 122         /// 123         /// 构造方法124         /// 125         public MainWindowViewModel()126         {127             People = new ObservableCollection();128 129             Person person1 = new Person() { Name = "小明", Age = 12, Sex = "男", Phone = "110" };130             Person person2 = new Person() { Name = "小红", Age = 13, Sex = "女", Phone = "119" };131             Person person3 = new Person() { Name = "小王", Age = 15, Sex = "男", Phone = "120" };132 133             People.Add(person1);134             People.Add(person2);135             People.Add(person3);136 137             TextInfo = "点击右侧按钮这里内容将会变化!";138         }139 140         /// 141         /// DataGrid控件中删除按钮事件142         /// 143         /// 可传入前台控件144         private void DeleteEvent(object obj)145         {146             if (MessageBox.Show($"是否删除{SelectItem.Name}的数据?", "提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes)147             {148                 People.Remove(SelectItem);149             }150         }151 152         /// 153         /// 前台添加小刚按钮事件154         /// 155         /// 可传入前台控件156         private void AdditionEvent(object obj)157         {158             if (MessageBox.Show("是否添加“姓名:小刚,年龄:18,性别:女,电话:123”?", "提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes)159             {160                 People.Add(new Person() { Name = "小刚", Age = 18, Sex = "女", Phone = "123" });161             }162         }163 164         /// 165         /// 前台修改Text按钮事件166         /// 167         /// 可传入前台控件168         private void ReviseEvent(object obj)169         {170             if (TextInfo == "点击右侧按钮这里内容将会变化!")171             {172                 TextInfo = "点击了右侧按钮!!!!!!!!!";173             }174             else175             {176                 TextInfo = "点击右侧按钮这里内容将会变化!";177             }178         }179 180         /// 181         /// DataGrid控件电话信息的TextBox键盘按下回车事件182         /// 183         /// 可传入前台控件184         private void PressEnterKeyEvent(object obj)185         {186             TextBox textBox = (TextBox)obj;187             MessageBox.Show($"点击了回车!控件内容为:{textBox.Text}");188         }189 190         /// 191         /// 数据结构192         /// 193         public class Person194         {195             public string Name { get; set; }196             public int Age { get; set; }197             public string Sex { get; set; }198             public string Phone { get; set; }199         }200     }201 }
MainWindowViewModel.cs

MainWindowsViewModel类中编写业务逻辑代码。

MainWindow.xaml代码:

1  9     10         11 12             13                 14                 15                 16                 17                     18                         19                             20                                 21                                     22                                 23                             24                         25                     26                 27                 28                     29                         30                             37         38         39     40 
MainWindow.xaml

MainWindow.xaml.cs

1 using System.Windows; 2  3 namespace WpfExample 4 { 5     public partial class MainWindow : Window 6     { 7         public MainWindow() 8         { 9             InitializeComponent();10             //绑定DataContext11             DataContext = new MainWindowViewModel();12         }13     }14 }
MainWindow.xaml.cs

实例效果:

主界面窗口,支持点击删除按钮删掉对应信息;支持修改姓名,年龄,性别,电话信息;支持修改电话信息按下回车键捕捉回车事件功能;支持点击左下角添加学生小刚按钮增加信息;支持点击右下角修改Text内容下方TextBlok控件内容变化。

点击删除按钮,弹出确认删除对话框,点击是则删除成功。

点击左下角“添加学生小刚”按钮,弹出是否确认添加小刚信息确认框,点击是则会添加小刚的信息。

在电话信息中输入回车会显示点击了回车弹框,并且显示控件中的内容。

点击右下角“修改Text内容按钮”下方TextBlock控件内容发生改变

修改小明的姓名后点击删除按钮,提示信息显示小明的姓名也被更改,说明数据源同时进行了更改。

1.数据源:数据绑定是通过ViewModel作为数据源,绑定到前台xaml进行实现的。通过后台对于数据源的修改,可以将内容直接同步到前台界面上。可以详见上面数据的删除和添加以及修改Text的实例。People、SelectItem、TextInfo都是数据源。

2.命令:除了数据要进行实时更新以外,前台的操作也应该能够传输到后台,在后台逻辑做出响应。这时我们需要用到Command(命令),在本实例中展示了将按钮的点击事件和键盘的回车事件通过命令的方式传到后台,但命令的用法远不止这两种,可以在实际的开发过程中跟据不同的需求在进行学习和尝试。值得注意的是命令是可以带参数的,前台代码中的CommandParameter就是它的参数,例如按钮点击的命令可以通过参数来确定点击的是哪一个按钮,当然也可以给每一个按钮绑定一个独立的命令。DelClick、AddClick、ReviseClick、PressEnterKey都是命令。

3.数据模板的重写:在本实例中重写了DataGrid控件中的电话一列和删除一列的数据模板,我们可以看到电话一列重写为了TextBox删除一列重写为了Button,表头也可以进行数据模板的重写。在DataTemplate中你可以写几乎任意的控件,如果需要放多个控件可以使用Grid和StackPanel这类布局控件进行封装。值得注意的是当重写数据模板之后,对于命令绑定的写法需要格外注意,需要注意Path和RelativeSource属性,详见例子代码中的写法,如果按照常规Binding的写法你会发现后端无法收到你绑定的命令。

4.双向绑定:顾名思义绑定是双向的,不仅仅是后台数据更新后自动同步到前台,同时前台的数据更新也会自动同步到后台。这种双向绑定也是MVVM设计模式的一大特点,本实例中可以看到修改了小明的名字后,修改的内容在你没有进行任何操作的情况下自动同步到了后台的数据源中(值得注意的是这里需要让选中的cell失去焦点修改的内容才会同步到后台数据源),这就是双向绑定。当然在绑定的过程中你可以设置多种模式,如果不设置默认为双向绑定,设置的方法是通过Mode属性(Binding="{Binding Name ,Mode=TwoWay}")你可以设置Default、OneTime、OneWay、OneWayToSource、TwoWay。

以上就是本实例中涉及一些要点,这些内容是做WPF和C#开发的基本内容,希望他们能对你的学习和工作起到一些帮助,如果对于本文某些用法写法说法有任何的意见欢迎指正交流。谢谢。

2023.4.17下午两点五十五分

标签:

C# WPF数据绑定方法以及重写数据模板后数据绑定

2023-04-17

【新要闻】中科通达上市首年由盈转亏 单一数字化业务寻求转型

2023-04-17

新时代首都发展巡礼 | 60万米高空看“绿色北京”|前沿资讯

2023-04-17

第30届北京大学生电影节特别活动汇总(时间+地点)

2023-04-17

苹果MR头显或亮相在即 能否开启“后iPhone时代”? 天天热点

2023-04-17

安徽省“三支一扶”计划招募1160人 焦点快看

2023-04-17

天天要闻:阿尔特塔:我们踢得太舒服了 要争冠不能只踢30分钟好球

2023-04-17

实时焦点:油服行业景气度持续上升 多家公司去年业绩亮眼今年新单不断

2023-04-17

天天快资讯丨4s店首保为啥不让人看

2023-04-17

情报站|滋滋啦啦!壹粉Vlog分享淄博烧烤,带你解锁新吃法-世界微资讯

2023-04-17

不以人废言原句 不以人废言

2023-04-17

香港哪个地方最穷?最高和最低相差近1倍|当前热点

2023-04-16

Intel鸡血驱动暴涨63%!Arc A750性价比秒杀RTX 3060 72%!

2023-04-16

手机正面还是背面辐射大?你穿的衣服也有辐射?大皖新闻记者带你揭秘-天天观热点

2023-04-16

女丽网邪恶网(女丽网)

2023-04-16

Redmi K60 Pro立减300 骁龙8 Gen2旗舰特价_即时看

2023-04-16

苯乙烯:供需逐步转弱,苯乙烯反弹承压 每日报道

2023-04-16

天天新消息丨补气的食物 补气的食物和水果有哪些

2023-04-16

每日热文:给妈妈送什么花好

2023-04-16

义乌江东货运市场

2023-04-16

国安有我 全民共护——各地各部门广泛开展全民国家安全教育日宣教活动

2023-04-16

2020广州丰华园第五届葡萄文化节 广州丰华园生态园游记

2023-04-16

当前滚动:七年级上册生物光合作用公式_光合作用公式

2023-04-16

做梦梦到掉牙齿是什么-梦见牙齿脱落是什么征兆 聚焦

2023-04-15

全球观速讯丨2023年4月15日碳酸二甲酯价格最新行情预测

2023-04-15

世界热头条丨五一机票大涨,出门穷游成奢望

2023-04-15

每日视点!女士优先

2023-04-15

明年起北京违规电动三、四轮车不得上路行驶,不得在公共场所停放

2023-04-15

太火爆!开售仅一小时 “五一”火车票多个车次已售罄_今日热门

2023-04-15

无限流量随身wifi_无限流量

2023-04-15

Copyright ©  2015-2022 欧洲频道网版权所有  备案号:沪ICP备2022005074号-23   联系邮箱: 58 55 97 3@qq.com