zoukankan      html  css  js  c++  java
  • WPF 中双向绑定通知机制之ObservableCollection使用

     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"}
                };
    
            public WindowObservable()
            {
                InitializeComponent();
    
                this.lbStudent.ItemsSource = infos;
    
                this.txtStudentId.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = lbStudent });
            }
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                infos[1] = new Students() { Id = 4, Age = 14, Name = "这是一个集合改变" };
                infos[2].Name = "这是一个属性改变";
            }
    
            public class Students
            {
                public int Id { get; set; }
                public string Name { get; set; }
                public int Age { get; set; }
            }    
        }
    }

    在这个例子中我们将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"}
                };
    
            public WindowObservable()
            {
                InitializeComponent();
    
                this.lbStudent.ItemsSource = infos;
    
                this.txtStudentId.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = lbStudent });
            }
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                infos[1] = new Students() { Id = 4, Age = 14, Name = "这是一个集合改变" };
                infos[2].Name = "这是一个属性改变";
            }
            public class Students : INotifyPropertyChanged
            {
                string _name;
                public int Id { get; set; }
                public string Name
                {
                    get { return _name; }
                    set { _name = value; OnPropertyChanged("Name"); }
                }
                public int Age { get; set; }
                protected internal virtual void OnPropertyChanged(string propertyName)
                {
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
                public event PropertyChangedEventHandler PropertyChanged;
            }
        }
    }

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

    使用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/

    转载请以超链接形式标明文章原始出处。
  • 相关阅读:
    笔记一 Redis基础
    (转载)你一定要努力,但千万别着急
    (转载)[jQuery]使用Uploadify(UploadiFive)多文件上传控件遇到的坑
    Redis学习笔记~StackExchange.Redis实现分布式Session
    转载 mvc中 将session保存到redis中 实现共享session
    webconfig配置信息转发
    2019.9.25-二分查找代码(递归和非递归方法)
    2019.9.24-常见排序算法效率比较【图】
    2019.9.24-归并排序(代码)
    2019.9.24-快速排序实现(完整代码)
  • 原文地址:https://www.cnblogs.com/santian/p/4366832.html
Copyright © 2011-2022 走看看