何时实现INotifyPropertyChanged接口

官方解释:INotifyPropertyChanged  接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知。官方解释的很模糊,估计是个人看了都不知道到底什么时候需要实现INotifyPropertyChanged接口.小梦通过实际测试给出明确结论:

首先:OneTime模式:毫无意义,因为它的绑定只有初始时候绑定一次,根本谈不上改变!自然也就谈不上实现INotifyPropertyChanged接口.

然后是OneWay模式:我们知道OneWay模式的含义是:绑定源的每一次变化都会通知绑定目标,但是绑定目标的改变不会改变绑定源.当绑定源的数据实体类没有实现INotifyPropertyChanged接口时,当我们改变了数据源,我们会发现绑定目标的UI上的相应的数据不会立即变化.所以这时候就需要我们来实现INotifyPropertyChanged接口.

最后是TwoWay模式:在TwoWay模式下,当绑定源的数据实体类没有实现INotifyPropertyChanged接口时,我们发现.控件的更改会让数据源立即发改变,但是改变数据源,绑定目标控件却不会立即发生改变!所以当我们需要数据源改变时相对应的UI立即改变时,就需要实现INotifyPropertyChanged接口.

总之:就是当数据源改变并需要UI立即改变时我们需要实现INotifyPropertyChanged接口.

我们可以通过这个示例来明确的体会这一点:

 
 
 
 
 
 

C#

 
<StackPanel>

<TextBox Header="编号" Text="{Binding ID,Mode=OneTime}" Name="tbxID" ></TextBox>

<TextBox Header="书名" Text="{Binding Title,Mode=OneWay}" Name="tbxTitle" ></TextBox>

<TextBox Header="价格" Text="{Binding Price,Mode=TwoWay}" Name="tbxPrice" ></TextBox>

<Button Content="通过数据源修改控件的值" Click="Button_Click"></Button>

<Button Content="直接修改控件的值" Click="Button_Click_1" />

<Button Content="通过控件修改数据源的值" Click="Button_Click_2" />

</StackPanel>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   <StackPanel>
 
       <TextBox  Header="编号" Text="{Binding ID,Mode=OneTime}" Name="tbxID"  ></TextBox>
 
        <TextBox Header="书名" Text="{Binding Title,Mode=OneWay}" Name="tbxTitle" ></TextBox>
 
       <TextBox  Header="价格" Text="{Binding Price,Mode=TwoWay}" Name="tbxPrice" ></TextBox>
 
     <Button Content="通过数据源修改控件的值"  Click="Button_Click"></Button>
 
         <Button Content="直接修改控件的值"     Click="Button_Click_1" />
 
        <Button Content="通过控件修改数据源的值"   Click="Button_Click_2" />
 
       </StackPanel>

后台代码:

 
 
 
 
 
 

C#

 
namespace INotifyPropertyChangedDEMO
{
/// <summary>
/// 可用于自身或导航至 Frame 内部的空白页。
/// </summary>

public sealed partial class MainPage : Page
{
Book book = new Book();
public MainPage()
{
this.InitializeComponent();

this.NavigationCacheMode = NavigationCacheMode.Required;
book.ID = 0;
book.Title = "ASP.NET 开发手册";
book.Price = 40;
st.DataContext = book;
}
private void Button_Click(object sender, RoutedEventArgs e)//通过修改数据源修改控件的值
{
book.ID = 100;
book.Price = 50;
book.Title = "SL开发手册";
}

private async void Button_Click_1(object sender, RoutedEventArgs e)//显示数据源的值
{
await new MessageDialog(book.ID.ToString() + " " + book.Title.ToString() + " " + book.Price.ToString()).ShowAsync();
}

public class Book : INotifyPropertyChanged
//INotifyPropertChanged 接口定义了一个当属性值更改时执行的事件,事件名称为PropertyChanged。
//这个是在继承这个接口的类必须要实现的事件

{
private int _id;
public int ID
{
get { return _id; }
set
{
_id = value;
//NotifyPropertyChange("ID");
}
}
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
//NotifyPropertyChange("Title");
}
}
private double _price;
public double Price
{
get { return _price; }
set
{
_price = value;
//NotifyPropertyChange("Price");
}
}
public event PropertyChangedEventHandler PropertyChanged;
//PropertyChangedEventArgs类型,这个类用于传递更改值的属性的名称,实现向客户端已经更改的属性发送更改通知。属性的名称为字符串类型。
private void NotifyPropertyChange(string propertyName)
{
if (PropertyChanged != null)
{
//根据PropertyChanged事件的委托类,实现PropertyChanged事件:
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
namespace INotifyPropertyChangedDEMO
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
 
    public sealed partial class MainPage : Page
    {
        Book book = new Book();
        public MainPage()
        {
            this.InitializeComponent();
 
            this.NavigationCacheMode = NavigationCacheMode.Required;
            book.ID = 0;
            book.Title = "ASP.NET 开发手册";
            book.Price = 40;
            st.DataContext = book;
        }
  private void Button_Click(object sender, RoutedEventArgs e)//通过修改数据源修改控件的值
        {
            book.ID = 100;
            book.Price = 50;
            book.Title = "SL开发手册";
        }
 
        private async void Button_Click_1(object sender, RoutedEventArgs e)//显示数据源的值
        {
            await new MessageDialog(book.ID.ToString() + " " + book.Title.ToString() + " " + book.Price.ToString()).ShowAsync();
        }
 
        public class Book : INotifyPropertyChanged
//INotifyPropertChanged 接口定义了一个当属性值更改时执行的事件,事件名称为PropertyChanged。
     //这个是在继承这个接口的类必须要实现的事件
 
        {
            private int _id;
            public int ID
            {
                get { return _id; }
                set
                {
                    _id = value;
                    //NotifyPropertyChange("ID");
                }
            }
            private string _title;
            public string Title
            {
                get { return _title; }
                set
                {
                    _title = value;
                    //NotifyPropertyChange("Title");
                }
            }
            private double _price;
            public double Price
            {
                get { return _price; }
                set
                {
                    _price = value;
                    //NotifyPropertyChange("Price");
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            //PropertyChangedEventArgs类型,这个类用于传递更改值的属性的名称,实现向客户端已经更改的属性发送更改通知。属性的名称为字符串类型。
            private void NotifyPropertyChange(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    //根据PropertyChanged事件的委托类,实现PropertyChanged事件:
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
}

大家运行这个示例可以明显体会INotifyPropertyChanged接口的作用.

如何实现INotifyPropertyChanged接口

上面示例的INotifyPropertyChanged接口的实现方式是最常见和最普遍的.

我们可以利用CallerMemberNameAttribute特性来简化一下,这个特性可以根据调用方来决定传入哪个属性的名字.:

 
 
 
 
 
 

C#

 
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
1
2
3
4
5
6
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var eventHandler = this.PropertyChanged;
            if (eventHandler != null)
                eventHandler(this, new PropertyChangedEventArgs(propertyName));
        }

这样我们在调用时可以这样调用:

NotifyPropertyChange(“ID”)  改为:OnPropertyChanged();

INotifyPropertyChanged接口的最佳实现方式:

这个所谓的最佳实现方式 是channel 9的视频中说的,实现方式如下:

 
 
 
 
 
 

C#

 
public class ModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
        {
            if (object.Equals(storage, value)) return false;
            storage = value;
            this.OnPropertyChanged(propertyName);
            return true;
        }
 
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var eventHandler = this.PropertyChanged;
            if (eventHandler != null)
                eventHandler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

相应的调用方式进一步简化:

 
 
 
 
 
 

C#

 
private string name;

public string Name
{
get { return name; }
set
{ this.SetProperty(ref this.name, value); }
}

1
2
3
4
5
6
7
8
   private string name;
 
        public string Name
        {
            get { return name; }
            set
            { this.SetProperty(ref this.name, value); }
        }
 
 
// 实现 INotifyPropertyChanged 是为了属性变更后的通知         public event PropertyChangedEventHandler PropertyChanged;         protected void NotifyPropertyChanged(string propertyName)         {             if (PropertyChanged != null)             {                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));             }         }

// 实现 INotifyPropertyChanging 是为了最大限度地减少内存使用量(NotifyPropertyChanging 的用法:在属性赋值之前调用)         /*          * 为什么会减少内存使用量呢?          * 因为 LINQ to SQL 更改跟踪是通过维护每个对象的两个副本进行工作的,第一个副本保存原始数据,第二个副本有程序更改,这样提交更新时 LINQ to SQL 就知道哪些数据被更改了,从而只提交这些被更改的数据          * INotifyPropertyChanging 接口允许应用程序在将修改后的数据提交到数据库前通知 DataContext,DataContext 可以将该通知用作创建副本的触发器,这样就不用保留第二个副本了,从而减少内存使用          */         public event PropertyChangingEventHandler PropertyChanging;         protected void NotifyPropertyChanging(string propertyName)         {             if (PropertyChanging != null)             {                 PropertyChanging(this, new PropertyChangingEventArgs(propertyName));             }         }

INotifyPropertyChanged接口的实现的更多相关文章

  1. 如何优雅的实现INotifyPropertyChanged接口

    INotifyPropertyChanged接口在WPF或WinFrom程序中使用还是经常用到,常用于通知界面属性变更.标准写法如下: class NotifyObject : INotifyProp ...

  2. INotifyPropertyChanged接口的PropertyChanged 事件

    INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知. 例如,考虑一个带有名为 FirstName 属性的 Person 对象. 若要提供 ...

  3. 【.NET深呼吸】INotifyPropertyChanged接口的真故事

    无论是在流氓腾的问问社区,还是在黑度贴吧,或是“厕所等你”论坛上,曾经看到过不少朋友讨论INotifyPropertyChanged接口.不少朋友认为该接口是为双向绑定而使用的,那么,真实的情况是这样 ...

  4. [译]WPF MVVM 架构 Step By Step(5)(添加actions和INotifyPropertyChanged接口)

    应用不只是包含textboxs和labels,还包含actions,如按钮和鼠标事件等.接下来我们加上一些像按钮这样的UI元素来看MVVM类怎么演变的.与之前的UI相比,这次我们加上一个"C ...

  5. 转载:WPF MVVM之INotifyPropertyChanged接口的几种实现方式

    原文地址:http://www.cnblogs.com/xiwang/ 序言 借助WPF/Sliverlight强大的数据绑定功能,可以比实现比MFC,WinForm更加优雅轻松的数据绑定.但是在使用 ...

  6. C# ListView 控件和 INotifyPropertyChanged 接口

    ListView 控件和 DataGridView 控件 ListView 是跟 Winform 中 DataGridView 用法以及显示效果差不多的一个 WPF 控件,可以通过列表的方式方便的显示 ...

  7. INotifyPropertyChanged 接口 CallerMemberName属性

    调用方信息 使用调用方信息属性,可以获取关于调用方的信息传递给方法. 可以获取源代码.行号在源代码和调用方的成员名称的文件路径. 此信息用于跟踪,调试和创建诊断工具非常有用.若要获取此信息,则使用适用 ...

  8. INotifyPropertyChanged 接口

    INotifyPropertyChanged 接口 用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知. 例如,考虑一个带有名为 FirstName 属性的 Person 对象.若要提供 ...

  9. 转载:如何优雅的实现INotifyPropertyChanged接口

    转载来源:http://www.cnblogs.com/TianFang/p/6240933.html 如何优雅的实现INotifyPropertyChanged接口 INotifyPropertyC ...

  10. ListView 控件和 INotifyPropertyChanged 接口

    原文:ListView 控件和 INotifyPropertyChanged 接口 ListView 控件和 DataGridView 控件 ListView 是跟 Winform 中 DataGri ...

随机推荐

  1. python3 操作appium

    # -*- coding: utf-8 -*- # @Time : 2018/10/8 11:00 # @Author : cxa # @File : test.py # @Software: PyC ...

  2. C/C++杂记:深入理解数据成员指针、函数成员指针

    1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针. 而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始地址的偏移值,空指针用-1表示.例: 代码示例: str ...

  3. tomcat -> 简介&部署

    Tomcat 简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun和其他一些公司及个人共同开 ...

  4. Eureka的自我保护模式

    一 Eureka的自我保护模式 进入自我保护模式最直观的体现就是Eureka Server首页的警告,如下图: 默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,E ...

  5. 使用node创建一个服务器,运行vue打包以后的文件

    原理就是使用node里的express框架,搭建一个服务器,然后访问dist文件夹里的文件 prod.server.js var express = require('express') var co ...

  6. 3.命名规范《.NET设计规范》

    3.命名规范 3.1 大小写约定 使用合适的大小写增强名字可读性. 3.1.1 标识符的大小写规则 标识符的每个单词首写字幕大写.不要用下划线. PascalCasing camelCasing Pa ...

  7. 启动DELPHI2010出现 EditorLineEnds.ttr 错误的解决方法

      在网上找到了很多方法.其实解决这个问题的方法, 最简单的就是把  EditorLineEnds.ttr  改名为  EditorLineEnds.ttf 然后,安装它, 安装完成后就OK了.

  8. 50 years, 50 colors HDU

    和棋盘游戏一个类型的题目 矩阵转换为二分图最大匹配问题   每次碰撞气球都是一行或一列 #include<bits/stdc++.h> using namespace std; #defi ...

  9. 记一次重装系统(.net开发环境重装问题汇总)

    起因: 有一天,我突然感觉到电脑的运行明显变慢,慢的可怕,启动任务资源管理器一看,不看不知道,一看吓一跳,CPU使用率,物理内存皆100%,当时的第一印象,是电脑中病毒了吧!!,进入进程一看,有几个名 ...

  10. 多线程学习笔记三之ReentrantLock与AQS实现分析

    目录 简介 AQS同步状态 AQS同步队列 ReentrantLock数据结构 公平锁的获取 tryAcquire(arg) addWaiter(Node mode) acquireQueued(fi ...