WPF 中双向绑定通知机制之ObservableCollection使用

WPF 中双向绑定通知机制之ObservableCollection使用

</div>

 msdn中   ObservableCollection<T> 类    表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知。

在许多情况下,所使用的数据是对象的集合。 例如,数据绑定中的一个常见方案是使用 ItemsControl(如 ListBoxListView 或 TreeView)来显示记录的集合。

可以枚举实现 IEnumerable 接口的任何集合。 但是,若要设置动态绑定,以便集合中的插入或删除操作可以自动更新 UI,则该集合必须实现 INotifyCollectionChanged 接口。 此接口公开 CollectionChanged 事件,只要基础集合发生更改,都应该引发该事件。

WPF 提供 ObservableCollection<T> 类,它是实现 INotifyCollectionChanged 接口的数据集合的内置实现。

还有许多情况,我们所使用的数据只是单纯的字段或者属性,此时我们需要为这些字段或属性实现INotifyPropertyChanged接口,实现了该接口,只要字段或属性的发生了改变,就会提供通知机制。

ObservableCollection<T>实现

前台xmal

复制代码
<Window x:Class="WpfApplication1.WindowObservable"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window8" Height="356" Width="471">
    <Grid>
        <StackPanel Height="295" HorizontalAlignment="Left" Margin="10,10,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="427">
            <TextBlock Height="23" Name="textBlock1" Text="学员编号:" />
            <TextBox Height="23" Name="txtStudentId" Width="301" HorizontalAlignment="Left"/>
            <TextBlock Height="23" Name="textBlock2" Text="学员列表:" />
            <ListBox Height="156" Name="lbStudent" Width="305" HorizontalAlignment="Left">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Name="stackPanel2" Orientation="Horizontal">
                            <TextBlock  Text="{Binding Id,Mode=TwoWay}" Margin="5" Background="Beige"/>
                            <TextBlock Text="{Binding Name,Mode=TwoWay}" Margin="5"/>
                            <TextBlock  Text="{Binding Age,Mode=TwoWay}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <Button Content="Button" Height="23" Name="button1" Width="75" HorizontalAlignment="Left" Click="button1_Click" />
        </StackPanel>
    </Grid>
</Window>
复制代码

后台cs

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace WpfApplication1
{
public partial class WindowObservable : Window
{
ObservableCollection<Students> infos = new ObservableCollection<Students>() {
new Students(){ Id=1, Age=11, Name=“Tom”},
new Students(){ Id=2, Age=12, Name=“Darren”},
new Students(){ Id=3, Age=13, Name=“Jacky”},
new Students(){ Id=4, Age=14, Name=“Andy”}
};

    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> WindowObservable()
    {
        InitializeComponent();

        </span><span style="color: #0000ff;">this</span>.lbStudent.ItemsSource =<span style="color: #000000;"> infos;

        </span><span style="color: #0000ff;">this</span>.txtStudentId.SetBinding(TextBox.TextProperty, <span style="color: #0000ff;">new</span> Binding(<span style="color: #800000;">"</span><span style="color: #800000;">SelectedItem.Id</span><span style="color: #800000;">"</span>) { Source =<span style="color: #000000;"> lbStudent });
    }
    </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span><span style="color: #000000;"> sender, RoutedEventArgs e)
    {
        infos[</span><span style="color: #800080;">1</span>] = <span style="color: #0000ff;">new</span> Students() { Id = <span style="color: #800080;">4</span>, Age = <span style="color: #800080;">14</span>, Name = <span style="color: #800000;">"</span><span style="color: #800000;">这是一个集合改变</span><span style="color: #800000;">"</span><span style="color: #000000;"> };
        infos[</span><span style="color: #800080;">2</span>].Name = <span style="color: #800000;">"</span><span style="color: #800000;">这是一个属性改变</span><span style="color: #800000;">"</span><span style="color: #000000;">;
    }

    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> Students
    {
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Id { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> Name { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Age { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }
    }    
}

}

复制代码

在这个例子中我们将Students数据对象用ObservableCollection<T>来修饰。这样当我们点击click的时候我们看到。当我们点击后只有student整个对象的改变引发了后台通知机制。

INotifyPropertyChanged实现

INotifyPropertyChanged会向客户端发出某一属性值已更改的通知。当元素属性值改变时,会通知后台model

前台代码不变,我们让后台Students  Model实现INotifyPropertyChanged接口。

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace WpfApplication1
{
public partial class WindowObservable : Window
{
ObservableCollection<Students> infos = new ObservableCollection<Students>() {
new Students(){ Id=1, Age=11, Name=“Tom”},
new Students(){ Id=2, Age=12, Name=“Darren”},
new Students(){ Id=3, Age=13, Name=“Jacky”},
new Students(){ Id=4, Age=14, Name=“Andy”}
};

    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> WindowObservable()
    {
        InitializeComponent();

        </span><span style="color: #0000ff;">this</span>.lbStudent.ItemsSource =<span style="color: #000000;"> infos;

        </span><span style="color: #0000ff;">this</span>.txtStudentId.SetBinding(TextBox.TextProperty, <span style="color: #0000ff;">new</span> Binding(<span style="color: #800000;">"</span><span style="color: #800000;">SelectedItem.Id</span><span style="color: #800000;">"</span>) { Source =<span style="color: #000000;"> lbStudent });
    }
    </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span><span style="color: #000000;"> sender, RoutedEventArgs e)
    {
        infos[</span><span style="color: #800080;">1</span>] = <span style="color: #0000ff;">new</span> Students() { Id = <span style="color: #800080;">4</span>, Age = <span style="color: #800080;">14</span>, Name = <span style="color: #800000;">"</span><span style="color: #800000;">这是一个集合改变</span><span style="color: #800000;">"</span><span style="color: #000000;"> };
        infos[</span><span style="color: #800080;">2</span>].Name = <span style="color: #800000;">"</span><span style="color: #800000;">这是一个属性改变</span><span style="color: #800000;">"</span><span style="color: #000000;">;
    }
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> Students : INotifyPropertyChanged
    {
        </span><span style="color: #0000ff;">string</span><span style="color: #000000;"> _name;
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Id { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> Name
        {
            </span><span style="color: #0000ff;">get</span> { <span style="color: #0000ff;">return</span><span style="color: #000000;"> _name; }
            </span><span style="color: #0000ff;">set</span> { _name = value; OnPropertyChanged(<span style="color: #800000;">"</span><span style="color: #800000;">Name</span><span style="color: #800000;">"</span><span style="color: #000000;">); }
        }
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Age { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }
        </span><span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">internal</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> OnPropertyChanged(<span style="color: #0000ff;">string</span><span style="color: #000000;"> propertyName)
        {
            </span><span style="color: #0000ff;">if</span> (PropertyChanged != <span style="color: #0000ff;">null</span><span style="color: #000000;">)
                PropertyChanged(</span><span style="color: #0000ff;">this</span>, <span style="color: #0000ff;">new</span><span style="color: #000000;"> PropertyChangedEventArgs(propertyName));
        }
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">event</span><span style="color: #000000;"> PropertyChangedEventHandler PropertyChanged;</span><span style="color: #000000;">
    }
}

}

复制代码

此时我们再 运行代码会发现

使用DataContext为页面对象设置上下文

不管是集合还是对象都发生了改变。至此。我们的整个后台通知就能完美监视任何对象变动。

但是现在还有一个问题。我们如果在点击事件里面给infos赋值一个新的集合数据。如下

复制代码
private void button1_Click(object sender, RoutedEventArgs e)
 {
            infos[1] = new Students() { Id = 4, Age = 14, Name = "这是一个集合改变" };
            infos[2].Name = "这是一个属性改变";
       infos = new ObservableCollection<Students>() { 
            new Students(){ Id=1, Age=11, Name="这是改变后的集合"},
            new Students(){ Id=2, Age=12, Name="这是改变后的集合"},
            new Students(){ Id=3, Age=13, Name="这是改变后的集合"},
            new Students(){ Id=4, Age=14, Name="这是改变后的集合"}
            };
}
复制代码

会发现数据并没有变更。这是为什么?我们明明实现了ObservableCollection<T>类型啊。这是因为infos这个集合的地址变更并没有实现通知机制。当我们new一个对象赋值给infos时候,infos的地址指向变更了。所以集合里面数据的变化,infos变更后的数据就参与绑定了。我们这时候可以通过DataContext实现数据数据项的变更通知。我们添加一个ViewModel类,实现INotifyPropertyChanged接口

复制代码
 public class ViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<Students> studentList;
        public ObservableCollection<Students> StudentList
        {
            get
            {
                return this.studentList;
            }
            set
            {
                if (this.studentList != value)
                {
                    this.studentList = value;
                    OnPropertyChanged("StudentList");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
复制代码

windowsObservable类修改为如下

复制代码
public partial class WindowObservable : Window
    {
        ViewModel viewModel = new ViewModel();
        public WindowObservable()
        {
            InitializeComponent();
            viewModel.StudentList = new ObservableCollection<Students>() { 
            new Students(){ Id=1, Age=11, Name="Tom"},
            new Students(){ Id=2, Age=12, Name="Darren"},
            new Students(){ Id=3, Age=13, Name="Jacky"},
            new Students(){ Id=4, Age=14, Name="Andy"}
            };
            this.lbStudent.DataContext = viewModel;
        }
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            viewModel.StudentList[1] = new Students() { Id = 4, Age = 14, Name = "这是一个集合改变" };
           
            viewModel.StudentList = new ObservableCollection<Students>() { 
            new Students(){ Id=19, Age=111, Name="这是变化后的几何"},
            new Students(){ Id=29, Age=121, Name="这是变化后的几何"},
            new Students(){ Id=39, Age=131, Name="这是变化后的几何"},
            new Students(){ Id=49, Age=141, Name="这是变化后的几何"}
            };
            viewModel.StudentList[2].Name = "这是一个属性改变";
        }
    }
复制代码

我们给xaml listbox设置如下绑定

ItemsSource="{Binding StudentList, Mode=TwoWay}"

运行程序我们发现集合的改变也会被通知到前台。

代码参考:http://blog.csdn.net/fwj380891124/article/details/8194190

本文地址:http://www.cnblogs.com/santian/p/4366832.html

博客地址:http://www.cnblogs.com/santian/

转载请以超链接形式标明文章原始出处。

 

分类: WPF
<div id="blog_post_info">
6
0
<div class="clear"></div>
<div id="post_next_prev">

<a href="https://www.cnblogs.com/santian/p/4362679.html" class="p_n_p_prefix">« </a> 上一篇:    <a href="https://www.cnblogs.com/santian/p/4362679.html" title="发布于 2015-03-24 17:42">PostgreSQL tips</a>
<br>
<a href="https://www.cnblogs.com/santian/p/4372667.html" class="p_n_p_prefix">» </a> 下一篇:    <a href="https://www.cnblogs.com/santian/p/4372667.html" title="发布于 2015-03-27 19:17">WPF 属性系统 依赖属性之内存占用分析</a>
posted on 2015-03-25 20:30  一天两天三天  阅读( 24842)  评论( 5编辑  收藏

FeedBack:
	<div class="feedbackItem">
		<div class="feedbackListTitle">

#1楼

2017-12-27 19:08

|

        <a id="a_comment_author_3875567" href="https://www.cnblogs.com/shinexyt/" target="_blank">17℃蓝</a>

很详细,感谢分享!
https://pic.cnblogs.com/face/u67141.jpg?id=26224859   
	</div>
	<div class="feedbackItem">
		<div class="feedbackListTitle">

#2楼

2018-01-10 16:21

|

        <a id="a_comment_author_3886189" href="https://www.cnblogs.com/liubo1/" target="_blank">liubo1</a>

写得很好,多谢

  

	</div>
	<div class="feedbackItem">
		<div class="feedbackListTitle">

#3楼

2018-02-27 17:41

|

        <a id="a_comment_author_3912138" href="https://www.cnblogs.com/tangyuan2016xi/" target="_blank">海的誓言</a>

很详细
https://pic.cnblogs.com/face/487742/20170929161541.png   
	</div>
	<div class="feedbackItem">
		<div class="feedbackListTitle">

#4楼

2019-01-18 09:55

|

        <a id="a_comment_author_4165597" href="https://home.cnblogs.com/u/1508414/" target="_blank">韩星途</a>

讲的很清楚,感谢。

  

	</div>
	<div class="feedbackItem">
		<div class="feedbackListTitle">

#5楼

    <span id="comment-maxId" style="display:none">4235220</span>
    <span id="comment-maxDate" style="display:none">2019/4/19 下午4:02:47</span>

2019-04-19 16:02

|

        <a id="a_comment_author_4235220" href="https://www.cnblogs.com/zlyxm/" target="_blank">zlyxm</a>

可能还有一点没考虑到,当viewModel.Remove() 移除的时候找有点麻烦..
https://pic.cnblogs.com/face/1143688/20170410154057.png   
	</div>
    <div id="google_ads_iframe_/1090369/C2_0__container__" style="border: 0pt none;"><iframe id="google_ads_iframe_/1090369/C2_0" title="3rd party ad content" name="google_ads_iframe_/1090369/C2_0" width="468" height="60" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" srcdoc="" style="border: 0px; vertical-align: bottom;" data-google-container-id="2" data-load-complete="true"></iframe></div></div>
</div>
<div id="under_post_kb">
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值