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

news2024/10/7 15:27:21

文章目录

  • 文章合集
  • 数据绑定
    • 数据绑定实战
      • 事件通知型
      • 数据驱动,双向绑定
        • 资源绑定
        • 数据源绑定
        • 全局数据源
        • 后端和前端绑定问题
        • 继承事件通知,刷新数据
        • 事件通知强制刷新(无效)
        • 结论:

文章合集

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; }
    }

在MainWindow.xmal.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;


    }

成功改变

在这里插入图片描述

我们将MainWindow.xmal.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认为这个不是活动窗口,所以刷新频率低一点,这个其实是个优化吧,多窗口默认优化。

结论:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/704109.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

365天深度学习训练营-第T4周:猴痘病识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 我的环境&#xff1a; 语言环境&#xff1a;Python3.10.7编译器&#xff1a;VScode深度学习环境&#xff1a;TensorFlow2 一、前期工作&#xff1a; 1、导入…

小白开酒吧前要知道的几个知识(一)

第一、团队建设如果决定开酒吧&#xff0c;除非你的资金充裕&#xff0c;否则都该寻找合伙人。共同的目标会让你和合伙人之间合作的更愉快&#xff0c;所以合伙人应该选择善于沟通交流的。选定靠谱的合伙人之后&#xff0c;应该建立一个大致的团队体系&#xff0c;在团队内做好…

CAD怎么转成清晰的图片?分享几种好用的转换方法

CAD文件通常需要特定软件才能打开和编辑&#xff0c;而将其转换为图片格式可以使其更加普遍地被浏览和共享。此外&#xff0c;由于图片通常具有较小的文件大小&#xff0c;因此转换为图片格式可以更快地上传和下载&#xff0c;可以方便地用于演示和分享。那么我们怎么把CAD文件…

Python进行单元测试是怎么做的?

前言 在我的日常工作中&#xff0c;我是一名专业程序员。我使用c、c#和Javascript。我是一个开发团队的一员&#xff0c;他们使用单元测试来验证我们的代码是否按照它应该的方式工作。 在本文中&#xff0c;我将通过讨论以下主题来研究如何使用Python创建单元测试。 单元测试…

一文详解Mac搭建Vulkan开发环境

本文为Vukan系列的第二篇文章&#xff0c;上一篇文章对Vulkan进行了简单介绍&#xff0c;并对其与OpenGL的优劣势进行了比较&#xff0c;为应用开发人员在选择图形API方面提供了建议。下边开始本文的主要内容&#xff0c;详细介绍在Mac操作系统中&#xff0c;如何搭建Vulkan开发…

力扣 98. 验证二叉搜索树

题目来源&#xff1a;https://leetcode.cn/problems/validate-binary-search-tree/description/ C题解1&#xff1a;中序遍历&#xff0c;递归法。获取数组&#xff0c;如果是递增则返回true&#xff0c;否则返回false。 class Solution { public:void zhongxu(TreeNode* node…

用vue3+elementplus做的一个滚动菜单栏的组件

目录 起因概览设计及解决思路1.滚动条竖起来2.绑定菜单3.吸附优化 组件全部代码 起因 在elementplus中看到了滚动条绑定了slider&#xff0c;但是这个感觉很不实用&#xff0c;在底部&#xff0c;而且横向滚动&#xff0c;最常见的应该是那种固定在左上角的带着菜单的滚动条&a…

MySQL总结(索引,Explain,MVCC和隔离级别,锁)

文章目录 一、索引1.索引构成2.如何查找3.最左匹配原则4.覆盖索引5.减少冗余索引和重复索引1.冗余索引2.重复索引 6.索引适用情况和注意事项1.适用情况2.注意事项 二、Explain执行计划1.Explain语句 三、隔离级别与MVCC1.事前准备2.四个事务并发的问题1.脏写2.脏读3.不可重复读…

(有10个维度为(256,128,130)的tensor,计算10个tensor两两之间的相似性以及差异性,并将相似性和差异性可视化。

有10个维度为&#xff08;256,128,130&#xff09;的tensor&#xff0c;计算10个tensor两两之间的相似性以及差异性&#xff0c;并将相似性和差异性可视化。 问题描述解决办法 问题描述 有10个维度为&#xff08;256,128,130&#xff09;的tensor&#xff0c;计算10个tensor两…

Java基础复习第二天

目录 一、字符串 二、不可变的好处 三、String&#xff0c; StringBuffer and StringBuilder的区别 四、字符串池 五、新字符串&#xff08;“abc”&#xff09; 一、字符串 String 被声明为 final&#xff0c;因此它不可被继承。&#xff08;Integer 等包装类也不能被继承…

前端-基础选择器

从今天开始学习下前端的知识-查漏补缺&#xff0c;仅为自己学习记录使用 基础选择器 标签选择器类选择器id 选择器通配符选择器 标签选择器 标签名 {属性名&#xff1a;属性值; }<style>p {color: red;} </style><p>你好&#xff0c;世界</p>类选择…

Unity URP 获取Camera Stack

URP 获取Camera Stack 1.using UnityEngine.Rendering.Universal; 2.Camera.main.GetUniversalAdditionalCameraData().cameraStack

【日志加载 log4j】

日志 笔记记录 1. 日志介绍2. 日志体系结构3.Log4j开发流程4.Log4j组成4.1 Loggers 记录器4.2 Appenders 输出源4.3 Layouts 布局5. 配置文件 log4j.properties 1. 日志介绍 2. 日志体系结构 3.Log4j开发流程 1.引入依赖<dependency><groupId>log4j</groupId>…

爬虫正常用哪种代理比较好?

在进行网络爬虫时&#xff0c;使用代理可以带来许多好处&#xff0c;包括提高请求的可靠性、防止IP封锁、实现匿名浏览等。以下是一些常见的代理类型&#xff0c;你可以根据需要选择最适合的&#xff1a; 免费代理&#xff1a;免费代理可能数量众多&#xff0c;但质量和稳定性参…

Python获取某品牌加盟数据采集实现可视化数据分析

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 开发环境 : python 3.8 运行代码 pycharm 2022.3 辅助敲代码 jupyter 数据分析使用软件 模块使用 &#xff1a; requests 数据请求模块 需要安装 parsel 数据解析模块 csv pandas pyecharts 第三方模块安装&#xf…

基于Java开发的企业人力资源管理系统(ehr系统)

一、项目介绍 一款全源码可二开&#xff0c;可基于云部署、私有部署的企业级数字化人力资源管理系统&#xff0c;涵盖了招聘、人事、考勤、绩效、社保、酬薪六大模块&#xff0c;解决了从人事招聘到酬薪计算的全周期人力资源管理&#xff0c;符合当下大中小型企业组织架构管理…

BOLD信号的生理建模及其对有效连接的影响

导读 本文提供了BOLD信号生理过程的总体概述(即生成生物物理模型)&#xff0c;包括它们在生理信息动态因果模型(P-DCM)框架下的时间过程特征。BOLD信号主要由顺磁性脱氧血红蛋白的变化决定&#xff0c;而顺磁性脱氧血红蛋白的变化是氧代谢、脑血流量和脑血容量变化共同作用的结…

测试工程师首chatGPT,编写python读取xmind测试用例chatgtp+python+xmind

背景 有用xmind写测试用例的吧&#xff0c;统计一个xmind的条&#xff0c;需要花大量的时间&#xff0c;还有要统计有多少条冒烟的&#xff0c;多少条不通过的&#xff0c;还有通过的条数。 需求 快速使用python&#xff0c;写一个简单的脚本&#xff0c;统计所有xmind节点&…

【IP地址与子网掩码】网络杂谈(19)之IP地址分类与子网掩码的概念

涉及知识点 什么是子网掩码&#xff0c;IP地址的分类&#xff0c;子网掩码的概念&#xff0c;深入了解子网掩码与IP地址,A类&#xff0c;B类&#xff0c;C类&#xff0c;D类&#xff0c;E类ip地址范围。 原创于&#xff1a;CSDN博主-《拄杖盲学轻声码》&#xff0c;更多内容可…

Linux调试笔记

gdb调试----------------------------------------------------------------------------------------- CMakeFile.txt加入set(CMAKE_BUILD_TYPE Debug) gdb ./rknn_MNIST 打断点 b 110/main(行号/函数名) 单步调试 s&#xff08;step&#xff09; 单步跳过 n&#xff08;n…