勇哥注:
此系列贴子服务于C# winform开发工程师,帮助他们快速了解wpf技术,节省大家的学习成本。
因此,这个系列不是讲给初学者听的。
我们知道winform是C#的标准ui框架,wpf则是另一种ui框架,随着.net Core的流行,它会是今后的主流选择,我们必须学习它。
系列贴子导航:
wpf的编程思想里有一条重要的,称为“数据驱动”。
我们知道winform是事件驱动的,wpf的数据驱动是明显有别于winform的一种方式。
下面我们做一件简单的事,引出“数据驱动”模式。
要求: 如果在一个文本框中输入了数值100,则自动将其文字颜色改为红色。
(一)用属性来实现
这样达的目的是,只要对属性Value赋值100,则文字变红色。
private string _value; public string Value { get { return _value; } set { _value = value; this.TxtAddr.Text = value; if (value == "100") this.TxtAddr.Foreground = Brushes.Red; } } public MainWindow() { InitializeComponent(); } private void ButRead_Click(object sender, RoutedEventArgs e) { this.Value = "100"; }
(二)用封装的类来实现
我们使用面向对象的方式做一个封装。
它用构造函数传入了主窗体,以操作控件。
注意勇哥这里起的名字MainViewModel, 它是指视图模型,它个名字的意义在后面第(四)节可以知道。
public class MainViewModel { MainWindow _win; public MainViewModel(MainWindow win) { _win = win; } private string _value; public string Value { get { return _value; } set { _value = value; _win.TxtAddr.Text = value; if (value == "100") _win.TxtAddr.Foreground = Brushes.Red; } } }
调用方法:
public MainViewModel model = null; public MainWindow() { InitializeComponent(); model = new MainViewModel(this); } private void ButRead_Click(object sender, RoutedEventArgs e) { model.Value = "100"; }
(三)控件属性绑定
例子二的控件操作其实可以使用xaml的绑定语法来实现。
首先我们把MainViewModel类改写一下。两个属性分别用于绑定文本框的Text和Foreground属性。
public class MainViewModel { private string _value="0"; public string Value { get { return _value; } set { _value = value; } } private Brush myColor= Brushes.Blue; public Brush MyColor { get { return myColor; } set { myColor= value; } } }
Xaml绑定语句如下:
注意几点:
要使用{},如果没有括号就是个普通字符
Value和MyColor是上面的MainViewModel类的两个属性。
绑定字符串这里VS2022还无法提供代码自动提示功能。
<TextBox Name="TxtAddr" Grid.Column="1" HorizontalAlignment="Left" Margin="84,131,0,0" TextWrapping="Wrap" Text="{Binding Value}" Foreground="{Binding MyColor}" VerticalAlignment="Top" Width="78"/>
光这样写上绑定语句还不够,此时还无法和MainViewModel类的两个属性建立关系。
你得在UI后台代码里为 DataContext赋值为MainViewModel类的实例。
private MainViewModel model = new MainViewModel(); public MainWindow() { InitializeComponent(); this.DataContext = model; } private void ButRead_Click(object sender, RoutedEventArgs e) { model.Value = "100"; }
现在运行后发现文本框显示出了默认的Value值和默认文本颜色MyColor,这证明绑定起作用了。
继续点击按钮让Value赋值100,此时问题来了。。。
你会发现文本框根本不更新内容,还是0。
(四)UI内容更新的事件通知
接下来解决更新ui的数据显示问题。
要点如下:
让MainViewModel类继承接口INotifyPropertyChanged,并且让接口自动实现
接口自动实现后会自动定义一个事件: public event PropertyChangedEventHandler? PropertyChanged;
此事件是wpf内部维护的,你不用去实现它,你只需要直接去使用它。
属性Value和MyColor,当值改变时,都需要进行事件通知(通知UI控件更新这个值到控件上面)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
public class MainViewModel:INotifyPropertyChanged { private string _value="0"; public string Value { get { return _value; } set { _value = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); if (value == "100") MyColor = Brushes.Red; } } private Brush myColor= Brushes.Blue; public event PropertyChangedEventHandler? PropertyChanged; public Brush MyColor { get { return myColor; } set { myColor= value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MyColor")); } } }
调用者:
private void ButRead_Click(object sender, RoutedEventArgs e) { model.Value = "100"; }
到了第四步后,对于ui的操作,基本上我们就可以称为由事件驱动方式过渡为了数据驱动方式。
使用者一句赋值 model.Value = "100"; 就已经完成控件内容更新(值由0变成100),以及逻辑处理后的控件更新(判断值为100则文字变红色)
勇哥总结下上面的数据驱动的几个注意点:
1. 数据驱动是由数据模型来推动UI动作的,上面的例子中的数据模型是MainViewModel类
而传统的操作控件的方式是直接赋值。
2. 数据驱动内部仍然使用的是事件通知完成UI更新
因此,并不是说有了数据驱动,事件驱动就没有意义了。
本文测试源代码下载:
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

