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/

轉載請以超鏈接形式標明文章原始出處。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM