WPF 零基础入门笔记(3):数据绑定详解

阅读: 评论:0

WPF 零基础入门笔记(3):数据绑定详解

WPF 零基础入门笔记(3):数据绑定详解

文章目录

  • 文章合集
  • 数据绑定
    • 数据绑定实战
      • 事件通知型
      • 数据驱动,双向绑定
        • 资源绑定
        • 数据源绑定
        • 全局数据源
        • 后端和前端绑定问题
        • 继承事件通知,刷新数据
        • 事件通知强制刷新(无效)
    • 补充说明:2023年7月15日
      • 使用ObservableCollection
      • 在Student里面设置通知
      • 安装prism框架,使用封装好的更新
        • 结论:

文章合集

WPF基础知识博客专栏
WPF微软文档
WPF控件文档

B站对应WPF数据绑定视频教程

数据绑定

我们在之前的文章中,详细解释了数据模版和控件模板。简单来说数据模板和控件模板就是为了解决代码重复的问题。我们可以回顾一下之前的所有内容。

  • 为了不写重复的样式,WPF提供了样式设置
  • 为了减少业务代码和界面之间的沟通,WPF将简单的交互逻辑设计到了触发器
  • 为了重复使用复杂控件,WPF开发了控件模板
    • 控件模板又分为
    • 多标签复合
    • 标签元素拆分
    • 标签子项重写

这个时候,为了数据的高效绑定,为了实现事件驱动到数据驱动的转变,我们要进行数据绑定。

数据绑定实战


基础样式

        <StackPanel><Slider x:Name="sd" Width="200" /><TextBox x:Name="txt" HorizontalAlignment="Center"  Text="50"/></StackPanel >

事件通知型

xml代码

        <StackPanel><Slider x:Name="sd" Width="200" ValueChanged="sd_ValueChanged"/><TextBox x:Name="txt" HorizontalAlignment="Center"  Text="50"/></StackPanel >

cs代码

        private void sd_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e){txt.Text = e.NewValue.ToString();}

实现效果

数据驱动,双向绑定

我们这里还是事件驱动,就是一个滑块移动事件来设置属性。WPF为了将这种简单的交互脱离业务逻辑,我们可以直接页面元素之间进行数据绑定。

        <StackPanel><Slider x:Name="sd" Width="200" /><TextBox x:Name="txt" HorizontalAlignment="Center"  Text="{Binding ElementName=sd, Path=Value}"/></StackPanel >

这个代码实现了双向绑定,而且没有在CS代码中写逻辑。这个是纯数据驱动事件。让我们的业务代码专心于业务。


功能
Default同TowWay。双向绑定
OneTime只响应一次
OneWay单向正绑定
OneWayToSource单向负绑定
TwoWay双向绑定

这里推荐大家用双向绑定,而且大部分业务也是双向绑定的业务。如果有特殊需求再更改。

资源绑定

我们还可以绑定静态资源

<Window.Resources><TextBox x:Key="txt">Hello WPF!</TextBox></Window.Resources><Grid><StackPanel><TextBox FontSize="50" Text="{Binding Source={StaticResource txt},Path=Text}"/></StackPanel ></Grid>

数据源绑定

我们之前都是前端的数据交互,我们希望直接绑定后端数据。通过使用dataContext来实现

        <StackPanel><TextBox x:Name="txt" FontSize="50" Text="{Binding Name}"/></StackPanel >
 public partial class MainWindow : Window{public MainWindow(){InitializeComponent();///获取前端名为txt的数据,传入数据源txt.DataContext = new Person(){Name = "Hello C#"};}}public class Person{public string Name { get; set; }}


注意,这里一定是传入一个类,这样才能绑定这个类的某个值。而且不能用已经存在的关键字命名。

全局数据源

我们一个一个绑定数据源太麻烦,所以我们可以设置全局数据源,把整个窗体的数据源都绑定上去。
新建一个MainViewModel类

    public class MainViewModel{public MainViewModel() {Name = "Hello WPF!";}public string Name { get; set; }}

在al.cs中引入MainViewModel

public partial class MainWindow : Window{public MainWindow(){InitializeComponent();//给整个窗口设置数据源this.DataContext = new MainViewModel();}}

直接绑定

    <Grid><StackPanel><TextBox FontSize="50"Text="{Binding Name}" /><TextBox FontSize="50"Text="{Binding Name}" /><TextBox FontSize="50"Text="{Binding Name}" /><TextBox FontSize="50"Text="{Binding Name}" /></StackPanel ></Grid>

后端和前端绑定问题

这里是单向绑定,后端代码更新是不影响前端的,要主动渲染。前端代码更新影响后端。

前端不重新渲染示例代码

    <Grid><StackPanel><TextBox FontSize="50"Text="{Binding Name}" /><TextBox FontSize="50"Text="{Binding Name}" /><TextBox FontSize="50"Text="{Binding Name}" /><TextBox FontSize="50"Text="{Binding Name}" /><Button Click="Button_Click" Height="100" FontSize="50" Content="按钮"/></StackPanel ></Grid>
    public partial class MainWindow : Window{MainViewModel data = new MainViewModel();public MainWindow(){InitializeComponent();//给整个窗口设置数据源this.DataContext = data;}//我们添加按钮事件同时打印值private void Button_Click(object sender, RoutedEventArgs e){data.Name = "data change!";MessageBox.Show(data.Name);}}

继承事件通知,刷新数据

在原来的基础上

    /// <summary>/// 继承INotifyPropertyChanged/// </summary>public class MainViewModel: INotifyPropertyChanged{public MainViewModel() {Name = "Hello WPF!";}/// <summary>/// 使用public类,不然无法双向绑定/// </summary>public string Name { get;set; }/// <summary>/// 重载事件类,不然会报错/// </summary>public event PropertyChangedEventHandler PropertyChanged;}

成功改变

我们将al.cs的点击按钮改造一下,看看多次点击会不会改变

public partial class MainWindow : Window{MainViewModel data = new MainViewModel();public MainWindow(){InitializeComponent();//给整个窗口设置数据源this.DataContext = data;}private void Button_Click(object sender, RoutedEventArgs e){data.Name += "!";MessageBox.Show(data.Name);}}
事件通知强制刷新(无效)

我把代码修改了一下,发现并不是强制通知,而是触发了事件,或者有点点击事件之后才会触发通知

MainViewModel代码

        public MainViewModel() {Name = "Hello WPF!";Task.Run(async () =>{await Task.Delay(3000);Name = "I have been changed!";MessageBox.Show(Name);});}/// <summary>/// 使用public类,不然无法双向绑定/// </summary>public string Name { get;set; }/// <summary>/// 重载事件类,不然会报错/// </summary>public event PropertyChangedEventHandler PropertyChanged;


如果你鼠标不动,则最多停留10s钟才会刷新,如果鼠标动一动就立刻刷新

 public class MainViewModel: INotifyPropertyChanged{public MainViewModel() {Name = "Hello WPF!";//Name = "I have been changed!";Task.Run(async () =>{await Task.Delay(3000);Name = "I have been changed!";//MessageBox.Show(Name);});}/// <summary>/// 使用public类,不然无法双向绑定/// </summary>private string _name;/// <summary>/// 当修改时触发/// </summary>public string Name{get { return _name; }set { _name = value; OnPropertyChanged("Name"); }}/// <summary>/// 重载事件类,不然会报错/// </summary>public event PropertyChangedEventHandler PropertyChanged;/// <summary>/// 强制事件通知/// </summary>/// <param name="propertyName"></param>protected void OnPropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}

结果还是一样。我估计是懒重载吧,就是WPF认为这个不是活动窗口,所以刷新频率低一点,这个其实是个优化吧,多窗口默认优化。

补充说明:2023年7月15日

根据我的测试。如果想要实先列表的数据绑定,比如我传入一个List<Student>类,Student有Name,Age参数。需要注意一下几点。

使用ObservableCollection

ObservableCollection是集成了INotifyPropertyChanged的集合,会在Count即个数出现变化的时候进行通知

在Student里面设置通知

进入如下参数设置

 public class MyListBoxItem : INotifyPropertyChanged{public string Text{get { return text; }set{text = value;OnPropertyChanged("Text");}}public event PropertyChangedEventHandler? PropertyChanged;//通知函数protected void OnPropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}

安装prism框架,使用封装好的更新

Nuget安装

    public class MyListBoxItem : BindableBase{private string text;public string Text{get { return text; }set {  SetProperty(ref text, value);}//此方法为Prism提供}}

可以输入propp加tab键,模板输入,提交写代码效率

我还是没有找到最优雅的解决方案,理论上最优解为:

  • 继承一个接口,所有的公共变量自动通知
  • 使用一个注解,被注解的参数自动赋值
  • 不需要定义私有类。

我只能猜测可能所有公共变量自动通知太过于危险了,需要我们手动输入。因为有模板输入,写代码也不是特别麻烦。

结论:

继承INotifyPropertyChanged,扩不扩展public属性,感觉效果差不多。出于简洁的目的,我们在WPF项目中就不用扩展了。

本文发布于:2024-01-31 20:05:29,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170670273131035.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:绑定   详解   入门   基础   笔记
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23