首页 > 其他分享 >3.数据绑定

3.数据绑定

时间:2024-01-29 11:03:33浏览次数:28  
标签:控件 绑定 ViewModel Person 数据 public 属性

什么是MVVM?看一张图。

View负责数据的输入与输出;ViewModel负责业务逻辑;Model则表示程序中具体要处理的数据。所以,Model将作为属性存在于ViewModel中,而Model最终是要显示在Ul界面(View)上的,怎么办呢?将ViewModel赋值给View的DataContext(数据上下文)属性,View就可以引用ViewModel中的那些Model了。

DataContext属性位于FrameworkElement类中,所以继承FrameworkElement类的控件都具有DataContext属性,包括Window类。

一般我们定义一个类,在窗体类的构造函数中赋值到窗体类的DataContext (object类型)属性中,因为窗体类继承了Window类。

this.DataContext = new MainViewModel();

 

Binding类架起了控件和ViewModel之间的桥梁,它就像一个媒婆,指示了哪个控件的哪个属性与哪个ViewModel类的哪个属性建立绑定关系。

4种绑定方式:

第一种:

Text="{Binding Person.Name}"

这里实例化了一个Binding对象,后面紧跟的Person.Name表示一个Path路径,指的是当前的DataContext中那个ViewModel对象的Person.Name

 

第二种:

<Window.Resources>
    <SolidColorBrush x:Key="RedBrush" Color="Red"/>
</Window.Resources>
Text="{Binding Source={StaticResource RedBrush},Path=Color}"

Source属性表示数据源对象,它是一个静态资源对象,Path=Color表示要绑定这个静态资源对象的Color属性。

第三种:

<StackPanel x:Name="panel" VerticalAlignment="Center" Margin="100,0">
    <TextBlock Margin="5">
        <Run Text="ElementName示例:"/>
        <Run Text="{Binding ElementName=panel,Path=Margin}"/>
    </TextBlock>
</StackPanel>

ElementName属性指明另一个控件作为数据源,这里仍然要用到Path来指定另一个控件的某个属性路径

 

第四种:

<StackPanel x:Name="panel" VerticalAlignment="Center" Margin="80,0">
    <TextBlock Margin="5">
        <Run Text="RelativeSource示例:"/>
        <Run Text="{Binding RelativeSource={RelativeSource Mode=Self},Path=Foreground}"/>
        <Run Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=StackPanel},Path=Margin}"/>
    </TextBlock>    
</StackPanel>

第一个RelativeSource:表示将自己的前景色显示到Text属性上。

第二个RelativeSource:表示从当前控件开始找上级,一个类型为StackPanel的控件,并把这个StackPanel控件的Margin显示到当前控件的Text属性上。

RelativeSource类有3个重要的属性,它们分别是Mode、AncestorType和AncestorLevel。

Mode:表示寻找相对数据源的模式,一共有4种模式

PreviousData 允许在当前显示的数据项列表中绑定上一个数据项(不是包含数据项的控件)。
TemplatedParent 引用应用了模板的元素,其中此模板中存在数据绑定元素。
Self 引用正在其上设置绑定的元素,并允许你将该元素的一个属性绑定到同一元素的其他属性上。
FindAncestor 引用数据绑定元素的父链中的上级。 这可用于绑定到特定类型的上级或其子类。

AncestorType:当Mode=FindAncestor时,这时就要指示要找的这个上级是什么类型,AncestorType用来表示上级的类型。

 AncestorLevel:获取或设置要查找的上级级别。 使用 1 指示最靠近绑定目标元素的项

 

 

五种绑定模式

当一个实体的属性绑定到控件的属性之后,还需要指明这两者之间的绑定关系。这个就是Binding类的Mode属性,Mode属性是一个枚举类型

TwoWay 双向绑定,即导致更改源属性或目标属性时自动更新另一方。
OneWay 单向绑定,在更改绑定源(源)时更新绑定目标(目标)。
OneTime 一次绑定,在应用程序启动或数据上下文更改时,更新绑定目标。
OneWayToSource 在目标属性更改时,更新源属性。
Default 默认绑定,文本框的默认绑定是双向的,而其他大多数属性默认为单向绑定。

这里面常用的是OneWay和TwoWay。如果是TwoWay(双向绑定),意味着前端控件的属性改变时,后端的Model也跟着改变,反之亦然。

如果前端的值发生改变,后端的值在什么时候跟着改变?它由Binding类的UpdateSourceTrigger属性的值决定 。这个属性也是一个枚举类型。

Default 采用控件各自的UpdateSourceTrigger默认值。
PropertyChanged 每当绑定目标属性发生更改时,都会更新绑定源。
LostFocus 每当绑定目标元素失去焦点时,都会更新绑定源。
Explicit 仅在调用 System.Windows.Data.BindingExpression.UpdateSource 方法时更新绑定源。

 

INotifyPropertyChanged接口

如果Model中的那些属性没有实现属性通知,就算前后端成功的建立了绑定关系,后端Model属性值改变时,前端的显示是没有变化的,如果要实时跟着变化,则需要掌握INotifyPropertyChanged接口以及属性通知。

INotifyPropertyChanged接口只有一个PropertyChanged事件,该事件专门用来触发属性更改通知。通常情况下,我们会单独编写一个服务类(例如ObservableObject),以实现INotifyPropertyChanged接口的业务。这样做的好处是,将来的ViewModel、Model都可以继承这个ObservableObject,从而调用属性通知接口。

namespace System.ComponentModel
{
    public interface INotifyPropertyChanged
    {
        //
        // 摘要:
        //     Occurs when a property value changes.
        event PropertyChangedEventHandler? PropertyChanged;
    }
}
public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
 
    public void RaisePropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

接下来,我们来编写一个ViewModel和一个Model,让它们都继承这个属性通知基类

Person实体

public class Person : ObservableObject
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value;RaisePropertyChanged(); }
    }
 
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; RaisePropertyChanged(); }
    }
 
    private string address;
    public string Address
    {
        get { return address; }
        set { address = value; RaisePropertyChanged(); }
    }
}

MainViewModel实体

public class MainViewModel : ObservableObject
{
    private Person person;
    public Person Person
    {
        get { return person; }
        set { person = value; RaisePropertyChanged(); }
    }
 
    public MainViewModel()
    {
        person = new Person
        {
            Name = "张三",
            Age = 50,
            Address = "居无定所",
        };
    }
}

当修改Name、Age、Address属性时,调用RaisePropertyChanged(),此时如果前端UI有这几个属性的绑定,将会立即被更新内容

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
 
            this.DataContext = new MainViewModel();
        }
}

 

INotifyCollectionChanged接口

除了INotifyPropertyChanged接口可以实现属性通知,还有一个接口也可以实现属性通知,它就是INotifyCollectionChanged。它的作用是:当添加和删除项或清除整个列表时,向侦听器通知动态更改。也就是说,它是专门来解决集合的元素数量发生变化时的通知问题的。

 

ObservableCollection<T>泛型集合是一个经常使用的集合,表示一个动态数据集合,它可在添加、删除项目或刷新整个列表时提供通知。它继承了INotifyCollectionChanged和INotifyPropertyChanged,表示它在元素数量发生变化时,前端界面也会同步发生变化。

 

它除了继承两个属性通知接口,还继承了一大波的接口,例如:IList, ICollection, IEnumerable, IEnumerable, IList, ICollection, IReadOnlyList, IReadOnlyCollection。所以,它拥有List集合同等的功能,而且,ObservableCollection还可以很方便的转换成List集合。

 

标签:控件,绑定,ViewModel,Person,数据,public,属性
From: https://www.cnblogs.com/MingQiu/p/17993881

相关文章

  • 向量数据库简介
    学习一下什么是向量数据库,原文地址:https://www.percona.com/blog/an-introduction-to-vector-databases/ 设想一下,地球的南半球即将进入冬季,而你想要去Patagonia旅行,因此你需要买几件舒适的衣服。你打开谷歌浏览器,并在搜索框输入"适合Patagonia天气的夹克衫",并没有考虑特......
  • 从传统到智能:物联网-交通数据运维平台的革新之路
    随着城市化进程的加速和科技的不断创新,交通问题已经成为影响城市发展的重要因素。而物联网技术的出现,为解决这一问题带来了全新的解决方案。 山海鲸可视化搭建的物联网-交通数据运维平台依托物联网技术,实现了对交通数据的全面、实时监控和管理,不仅改变了传统的交通管理模式,更让......
  • 使用核模型高斯过程(KMGPs)进行数据建模
    核模型高斯过程(KMGPs)作为一种复杂的工具可以处理各种数据集的复杂性。他通过核函数来扩展高斯过程的传统概念。本文将深入探讨kmgp的理论基础、实际应用以及它们所面临的挑战。核模型高斯过程是机器学习和统计学中对传统高斯过程的一种扩展。要理解kmgp,首先掌握高斯过程的基础......
  • MySQL数据库连接报错1130 - Host 'xxx' is not allowed to connect to this MySQL ser
    目录现象描述原因分析解决办法:本文解决MySQL数据库连接报错1130-Host'xxx'isnotallowedtoconnecttothisMySQLserver。返回目录返回目录现象描述MySQL数据库,使用Navicat、root用户连接报错:原因分析这个报错原因是权限问题,需要修改连接权限。进入mysql......
  • 通过 dba_hist_active_sess_history 分析数据库历史性能问题
    1.Dump出问题期间的ASH数据SQL>connuser/passwdSQL>createtablet_ashasselect*fromdba_hist_active_sess_historywhereSAMPLE_TIMEbetweenTO_TIMESTAMP('<time_begin>','YYYY-MM-DDHH24:MI:SS')andTO_TIMESTAMP('<t......
  • MySQL批量修改数据表编码及字符集为utf8mb4
    utf8mb4编码是utf8编码的超集,兼容utf8,并且能存储4字节的表情字符。 采用utf8mb4编码的好处是:存储与获取数据的时候,不用再考虑表情字符的编码与解码问题。更改数据库的编码为utf8mb4:1.MySQL的版本utf8mb4的最低mysql版本支持版本为5.5.3+,若不是,请升级到较新版本。2.MySQL......
  • 案例分享:一个数据丢失惨案
    前言最近,有开发同事联系我反馈一个问题,说开发环境出现了数据丢失的情况,想让DBA帮忙排查一下是不是数据库的问题。我心想大概率是程序bug,不太可能是数据库的问题。不过还是要排查一下才会心安,毕竟对于一个DBA而言,数据丢失无疑是最令人紧张的一件事情。问题排查开始进行排查之前,......
  • 在K8S中,怎样实现数据持久化?
    在Kubernetes(简称K8s)中,数据持久化是通过Volume机制来实现的。Volume是一个抽象概念,它代表了Pod能够访问的存储资源,这些资源可以是本地磁盘、网络文件系统(NFS)、云提供商提供的块存储或对象存储等。以下是Kubernetes实现数据持久化的关键组件和过程:Volume:Volume为Pod提供了一......
  • 经典数据结构题目-树
    树105.从前序与中序遍历序列构造二叉树思路先序遍历中,树的根节点放在第一位,后面是左右子树。中序遍历中,树的根节点放在中间,两边分为左右子树可基于以上规则区分出每棵树在数组中的区间先从先序数组中拿到根节点的val因为val不重复,定位到该树在中序数组的位置中序数......
  • 动态绑定组件时 v-model:value 的使用
    //requireimportcomponentsconstfiles=require.context("@/components/control",true,/\index.vue$/);//console.log('files:',files.keys())//files:['./cascader/index.vue','./control/cascader/index.vue',......