首頁 > 資料庫 > mysql教程 > WPF数据绑定(2 绑定列表数据Binding to List Data)

WPF数据绑定(2 绑定列表数据Binding to List Data)

WBOY
發布: 2016-06-07 15:48:52
原創
1407 人瀏覽過

(读完此系列WPF和Silverlight的数据绑定问题你就轻松搞定 ) 1 Binding to List Data 前面都是绑定到一个对象,下面我们学习绑定到对象列表的方法。 我们还是先组织要绑定的数据,对象所对应的类还是Person,但新增了一个新类People,该类用来组织Person的列

(读完此系列WPF和Silverlight的数据绑定问题你就轻松搞定WPF数据绑定(2 绑定列表数据Binding to List Data)

1 Binding to List Data

前面都是绑定到一个对象,下面我们学习绑定到对象列表的方法。

我们还是先组织要绑定的数据,对象所对应的类还是Person,但新增了一个新类People,该类用来组织Person的列表.代码如下:

<span>using </span>System;
            <span>using </span>System.Collections.Generic;
            <span>using </span>System.ComponentModel;<span>//INotifyPropertyChanged
            </span><span>namespace </span>SimpleDataBinding
            {
            <span>class </span><span>Person </span>: <span>INotifyPropertyChanged
            </span>{
            <span>public event </span><span>PropertyChangedEventHandler </span>PropertyChanged;
            <span>protected void </span>Notify(<span>string </span>PropName)
            {
            <span>if </span>(<span>this</span>.PropertyChanged != <span>null</span>)
            {
            PropertyChanged(<span>this</span>, <span>new </span><span>PropertyChangedEventArgs</span>(PropName));
            }
            }
            <span>public </span>Person()
            {
            _Age = 0;
            _name = <span>"Null"</span>;
            <span>this</span>.CurrentDate = <span>DateTime</span>.Now;
            }
            <span>private string </span>_name;
            <span>public string </span>Name
            {
            <span>get </span>{ <span>return </span>_name; }
            <span>set
            </span>{
            <span>if </span>(<span>value </span>== _name)
            { <span>return</span>; }
            _name = <span>value</span>;<span>//注意:不能用this.Name来赋值,如果这样形成循环调用,栈溢出
            </span>Notify(<span>"Name"</span>);
            }
            }
            <span>private int </span>_Age;
            <span>public int </span>Age
            {
            <span>get </span>{ <span>return </span>_Age; }
            <span>set
            </span>{
            <span>if </span>(<span>value </span>== _Age) <span>return</span>;
            _Age = <span>value</span>;
            Notify(<span>"Age"</span>);
            }
            }
            <span>public </span><span>DateTime </span>CurrentDate { <span>get</span>; <span>set</span>; }
            }
            <strong><span><span>//People类
            </span><span>class </span><span>People </span>: <span>List</span>Person</span>>
            {
            }</strong>
            }
            
登入後複製

注意在同一命名空间下的代码最后添加了Perople类。

我们在UI里显示的XAML如下:

<span><span>Window </span><span>x</span><span>:</span><span>Class</span><span>="ListDataBinding.BindListDataTest"
            </span><span>xmlns</span><span>="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            </span><span>xmlns</span><span>:</span><span>x</span><span>="http://schemas.microsoft.com/winfx/2006/xaml"
            <u> </u></span><strong><u><span><span>xmlns</span><span>:</span><span>src</span></span></u></strong><span><strong><u><span>="clr-namespace:ListDataBinding"</span></u></strong>
            </span><span>Title</span><span>="BindListDataTest" </span><span>Height</span><span>="113" </span><span>Width</span><span>="300">
            <span>Window.Resources</span><span>>
            <span> <strong></strong></span></span><span><strong><span>src</span><span>:</span><span>People </span><span>x</span><span>:</span><span>Key</span></strong></span><span><span><strong>="Family"></strong></span>
            <span>src</span><span>:</span><span>Person </span><span>Name</span><span>="Jack" </span><span>Age</span><span>="18"/>
            <span>src</span><span>:</span><span>Person </span><span>Name</span><span>="Tom" </span><span>Age</span><span>="30"/>
            <span>src</span><span>:</span><span>Person </span><span>Name</span><span>="Jone" </span><span>Age</span><span>="14"/>
            <span>src</span><span>:</span><span>Person </span><span>Name</span><span>="Rose" </span><span>Age</span><span>="17"/>
            <span>src</span><span>:</span><span>Person </span><span>Name</span><span>="Mike" </span><span>Age</span><span>="13"/>
            </span><span>src</span><span>:</span><span>People</span><span>>
            </span><span>Window.Resources</span><span>>
            <span>Grid </span><span>DataContext</span><span>="{</span><span>StaticResource </span><span>Family</span><span>}">
            <span>Grid.RowDefinitions</span><span>>
            <span>RowDefinition</span><span>/>
            <span>RowDefinition</span><span>/>
            </span><span>Grid.RowDefinitions</span><span>>
            <span>Grid.ColumnDefinitions</span><span>>
            <span>ColumnDefinition </span><span>Width</span><span>="80"/>
            <span>ColumnDefinition </span><span>Width</span><span>="*"/>
            </span><span>Grid.ColumnDefinitions</span><span>>
            <span>TextBlock </span><span>Grid.Row</span><span>="0" </span><span>Grid.Column</span><span>="0" </span><span>Text</span><span>="Name" </span><span>TextAlignment</span><span>="Center" </span><span>VerticalAlignment</span><span>="Center"/>
            <span>TextBlock </span><span>Grid.Row</span><span>="1" </span><span>Grid.Column</span><span>="0" </span><span>Text</span><span>="Age" </span><span>TextAlignment</span><span>="Center" </span><span>VerticalAlignment</span><span>="Center"/>
            <span>TextBox </span><span>Grid.Row</span><span>="0" </span><span>Grid.Column</span><span>="1" </span><span>Name</span><span>="txtName" </span><strong><span><span>Text</span><span>="{</span><span>Binding </span><span>Path</span></span></strong><span><strong><span>=Name}"</span></strong> />
            <span>TextBox </span><span>Grid.Row</span><span>="1" </span><span>Grid.Column</span><span>="1" </span><span>Name</span><span>="txtAge" </span><span><strong><span>Text</span><span>="{</span><span>Binding </span><span>Path</span></strong></span><span><span><strong>=Age}"/</strong></span>>
            </span><span>Grid</span><span>>
            </span><span>Window</span><span>>
            </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
登入後複製

我们发现这样的UI只能显示第一个数据项目,也就是说列表的当前项为0,至于其他的就无法显示出来了。

如果要显示其他的只有可通过如下代码的方式来取(注意:书中代码似乎有问题):

<span>private void </span>btnNext_Click(<span>object </span>sender, <span>RoutedEventArgs </span>e)
            {
            <span>People </span>people = (<span>People</span>)<span>this</span>.FindResource(<span>"Family"</span>);
            txtName.Text = people[1].Name;
            txtAge.Text = people[1].Age.ToString();
            }
登入後複製

 

1.1当前项Current Item

取得当前项

可以通过上面的方法取得当前项,当然我们更专业的做法还是使用Collection View

还是代码说明比较简洁:

<span>People </span>people = (<span>People</span>)<span>this</span>.FindResource(<span>"Family"</span>);
            <span>ICollectionView </span>view = <span>CollectionViewSource</span>.GetDefaultView(people);
            <span>Person </span>peron = (<span>Person</span>)view.CurrentItem;
登入後複製

注意:ICollectionView在System.ComponentModel命名空间里。

导航当前项

还是代码来说明更合适点:

<span>      private </span><span>ICollectionView </span>GetView()
            {
            <span>People </span>people = (<span>People</span>)<span>this</span>.FindResource(<span>"Family"</span>);
            <span>ICollectionView </span>view = <span>CollectionViewSource</span>.GetDefaultView(people);
            <span>return </span>view;
            }
            <span>private void </span>btnNext_Click(<span>object </span>sender, <span>RoutedEventArgs </span>e)
            {
            <span>ICollectionView </span>view = GetView();
            view.MoveCurrentToNext();
            <span>if </span>(view.IsCurrentAfterLast)
            {
            view.MoveCurrentToLast();
            }
            }
            <span>private void </span>btnPrior_Click(<span>object </span>sender, <span>RoutedEventArgs </span>e)
            {
            <span>ICollectionView </span>view = GetView();
            view.MoveCurrentToPrevious();
            <span>if </span>(view.IsCurrentBeforeFirst)
            {
            view.MoveCurrentToFirst();
            }
            }
登入後複製
1.2 List Data Targets

我们将列表数据绑定到类似TextBox这样的控件难以很好地展现列表数据。我们考虑ListBox控件来列举多个数据信息。

这时的效果如下:列表确实显示了所有对象的信息,因为我们没有设置Path属性,所以采用默认的Convertation来处理,显示对象类型。同时一定要注意使用IsSynchronizatizedWithCurrentItem=True,这样才能列表信息与其他信息同步。但究竟如何才能更好地表达我们需要的信息呢,请参看下一节:

WPF数据绑定(2 绑定列表数据Binding to List Data)

1.3 Display Members, Value Members, and Look-Up Bindings

代码示例也许更易理解:

<span><span>ListBox </span><span>Grid.Row</span><span>="3" </span><span>Grid.Column</span><span>="1" </span><span>Name</span><span>="lstbox" </span><span>ItemsSource</span><span>="{</span><span>Binding</span><span>}"
            </span><span>DisplayMemberPath</span><span>="Name" </span><span>SelectedValuePath</span><span>="Age" </span><span>IsSynchronizedWithCurrentItem</span><span>="True"/>
            <span>Button </span><span>Grid.Row</span><span>="4" </span><span>Grid.Column</span><span>="0" </span><span>Name</span><span>="btnShowValue" </span><span>Content</span><span>="ShowValue" </span><span>Click</span><span>="btnShowValue_Click" /></span></span></span>
登入後複製
<span>private void </span>btnShowValue_Click(<span>object </span>sender, <span>RoutedEventArgs </span>e)
            {
            <span>MessageBox</span>.Show(lstbox.SelectedValue.ToString());
            }
登入後複製
1.4数据模板Data Templates

这是利用ListBox控件有一个ItemTemplate属性下面,他可以接受一个DataTemplate类实例,

该模板可以重复绑定到ListBox的每一个项目元素,注意DataTemplate只能指定一个孩子节点,所以一般使用容器控件来组织下面的布局。

<span><span>ListBox </span><span>Grid.Row</span><span>="3" </span><span>Grid.Column</span><span>="1" </span><span>Name</span><span>="lstbox" </span><span>ItemsSource</span><span>="{</span><span>Binding</span><span>}">
            <span>ListBox.ItemTemplate</span><span>>
            <span>DataTemplate</span><span>>
            <span>TextBlock </span><span>Text</span><span>="{</span><span>Binding </span><span>Path</span><span>=Name}">
            </span><span>的年龄是</span><span><span>TextBlock </span><span>Text</span><span>="{</span><span>Binding </span><span>Path</span><span>=Age}"></span><span>TextBlock</span><span>>
            </span><span>TextBlock</span><span>>
            </span><span>DataTemplate</span><span>>
            </span><span>ListBox.ItemTemplate</span><span>>
            </span><span>ListBox</span><span>></span></span></span></span></span></span>
登入後複製
<span>我本人不赞同书中这样的做法,添加一个StackPanel更舒服点。</span>
登入後複製

 

1.5 列表改变List Changes

当我们改变列表的数据的时候,却出现如下现象:

WPF数据绑定(2 绑定列表数据Binding to List Data)

只是因为我们需要绑定的列表需要实现INotifyCollectionChanged接口:

<span>namespace </span>System.Collections.Specialized
            {
            <span>public interface </span><span>INotifyCollectionChanged
            </span>{
            <span>event </span><span>NotifyCollectionChangedEventHandler </span>CollectionChanged;
            }
            }
登入後複製

 

<span>namespace </span>System.Collections.ObjectModel
            {
            <span>public class </span><span>ObservableCollection</span><t> : <span>Collection</span><t>, INotifyCollectionChanged, <span>INotifyPropertyChanged
            </span>{
            ...
            }
            }</t></t>
登入後複製

欢呼雀跃吧,我们改变上面例题的代码,一切如我们想象的美好。

所有的一切就如此简单,简单代码改动:

<span>//People类
            </span><span>class </span><span>People </span>: <span><strong><span>ObservableCollection</span></strong></span>Person>
            {
            }
登入後複製

WPF数据绑定(2 绑定列表数据Binding to List Data)

1.6 排序Sorting

简单的代码还是足以繁杂的文字,让我们看如下方法:

<span>       private void </span>btnSort_Click(<span>object </span>sender, <span>RoutedEventArgs </span>e)
            {
            <span>ICollectionView </span>view = GetView();
            <span>if </span>(view.SortDescriptions.Count == 0)
            {
            view.SortDescriptions.Add(<span>new </span><span>SortDescription</span>(<span>"Name"</span>, <span>ListSortDirection</span>.Ascending));
            view.SortDescriptions.Add(<span>new </span><span>SortDescription</span>(<span>"Age"</span>, <span>ListSortDirection</span>.Descending));
            }
            <span>else
            </span>{
            view.SortDescriptions.Clear();
            }
            }
登入後複製

当然我们还可以自定义排序方式:

<span>    class </span><span>PersonSorter</span>:<span>IComparer
            </span>{
            <span>public int </span>Compare(<span>object </span>x, <span>object </span>y)
            {
            <span>Person </span>lhs = (<span>Person</span>)x;
            <span>Person </span>rhs = (<span>Person</span>)y;
            <span>// Sort Name ascending and Age descending
            </span><span>int </span>nameCompare = lhs.Name.CompareTo(rhs.Name);
            <span>if </span>(nameCompare != 0) <span>return </span>nameCompare;
            <span>return </span>rhs.Age - lhs.Age;
            }
            }
登入後複製

注意:WPF不使用System.Collection.Generic命名空间的泛型IComparer接口,而是使用System.Collection的。呵呵。

使用代码如下:

<span>       private void </span>btnSort_Click(<span>object </span>sender, <span>RoutedEventArgs </span>e)
            {
            <span>ListCollectionView </span>view = (<span>ListCollectionView</span>)GetView();
            <span>if </span>(view.CustomSort == <span>null</span>)
            {
            view.CustomSort = <span>new </span><span>PersonSorter</span>();
            }
            <span>else
            </span>{
            view.CustomSort = <span>null</span>;
            }
            }
登入後複製

注意:ListCollectionView支持自定义和排序,其他的不支持。

1.7 集合缺省视图类型Default Collection View

WPF数据绑定(2 绑定列表数据Binding to List Data)

1.8 过滤 Filter

依然是我熟悉的表达方式:代码:

<span>       private void </span>btnFilter_Click(<span>object </span>sender, <span>RoutedEventArgs </span>e)
            {
            <span>ListCollectionView </span>view = (<span>ListCollectionView</span>)GetView();
            <span>if </span>(view.Filter == <span>null</span>)
            {
            view.Filter = <span>delegate</span>(<span>object </span>item)
            {
            <span>return </span>((<span>Person</span>)item).Age > 17;
            };
            }
            <span>else
            </span>{
            view.Filter = <span>null</span>;
            }
            }
登入後複製
1.9 分组Grouping

分组的意思大家很明白就是按照某一个或几个关键属性进行分类。

进行分组很简单和sort类似,只需要以下几行代码:

<span>          ICollectionView </span>view = GetView();
            <span>if </span>(view.GroupDescriptions.Count == 0)
            {
            view.GroupDescriptions.Add(<span>new </span><span>PropertyGroupDescription</span>(<span>"Age"</span>));
            }
            <span>else
            </span>{
            view.GroupDescriptions.Clear();
            }
登入後複製

但这在UI层面并没有任何影响,这需要我们对ItemsControl类的控件(例如ListBox)设置GroupStyle属性,GroupStyle类缺省地提供了一个静态的属性实现,我们可以如下设置:

<span>      <span>ListBox </span><span>Grid.Row</span><span>="3" </span><span>Grid.Column</span><span>="1" </span><span>Name</span><span>="lstbox" </span><span>ItemsSource</span><span>="{</span><span>Binding</span><span>}"  </span><span>IsSynchronizedWithCurrentItem</span><span>="True">
            <strong><span></span></strong></span><span><strong><span>ListBox.GroupStyle</span></strong></span><strong><span><span>>
            <span>x</span><span>:</span><span>Static </span><span>Member</span></span><span><span>="GroupStyle.Default"/>
            </span><span>ListBox.GroupStyle</span></span></span></strong><span><strong><span>></span></strong>
            <span>ListBox.ItemTemplate</span><span>>
            <span>DataTemplate</span><span>>
            <span>TextBlock </span><span>Text</span><span>="{</span><span>Binding </span><span>Path</span><span>=Name}">
            </span><span>的年龄是</span><span><span>TextBlock </span><span>Text</span><span>="{</span><span>Binding </span><span>Path</span><span>=Age}"></span><span>TextBlock</span><span>>
            </span><span>TextBlock</span><span>>
            </span><span>DataTemplate</span><span>>
            </span><span>ListBox.ItemTemplate</span><span>>
            </span><span>ListBox</span><span>></span></span></span></span></span></span>
登入後複製

但也许这并不是我们所喜欢的界面,简单得让人生厌,还好微软提供了这个对象的一个属性:HeaderTemplate用于定义分组的栏目的外观,微软总是为大家想得那么周到,养活那么多天才是需要钱的,希望大家不要老是讲微软的坏话。

<span>           <span>ListBox.GroupStyle</span><span>>
            <span>GroupStyle</span><span>>
            <span>GroupStyle.HeaderTemplate</span><span>>
            <span>DataTemplate</span><span>>
            <span>StackPanel </span><span>Background</span><span>="Green"  </span><span>Orientation</span><span>="Horizontal">
            <span>TextBlock </span><span>Text</span><span>="{</span><span>Binding </span><span>Name</span><span>}"/>
            <span>TextBlock </span><span>Text</span><span>="("/>
            <span>TextBlock </span><span>Text</span><span>="{</span><span>Binding </span><span>ItemCount</span><span>}"/>
            <span>TextBlock </span><span>Text</span><span>=")"/>
            </span><span>StackPanel</span><span>>
            </span><span>DataTemplate</span><span>>
            </span><span>GroupStyle.HeaderTemplate</span><span>>
            </span><span>GroupStyle</span><span>>
            </span><span>ListBox.GroupStyle</span><span>></span></span></span></span></span></span></span></span></span></span>
登入後複製

有这模板属性一切由你发挥,真是好也,然而即使这样解决了UI问题,但是如果我们还希望更进一步,能否实现范围内分组呢?呵呵,然也:

这时我们不需要去想着如何继承GroupStyle类,而是采用围魏救赵的方式,定义一个IValueConverter,

<span>   public class </span><span>AgeRangeConvert </span>: <span>IValueConverter
            </span>{
            <span>public object </span>Convert(<span>object </span>value, <span>Type </span>targetType, <span>object </span>parameter, <span>CultureInfo </span>culture)
            {
            <span>int </span>_value = (<span>int</span>)value;
            <span>if </span>(_value return <span>"10岁以下"</span>;
            <span>else if </span>(_value return <span>"20岁以下"</span>;
            <span>else
            return </span><span>"20岁以上"</span>;
            }
            <span>public object </span>ConvertBack(<span>object </span>value, <span>Type </span>targetType, <span>object </span>parameter, <span>CultureInfo </span>culture)
            {
            <span>throw new </span><span>NotImplementedException</span>();
            }
            }
登入後複製

简单调整前面分组代码:

<span>           ICollectionView </span>view = GetView();
            <span>if </span>(view.GroupDescriptions.Count == 0)
            {
            view.GroupDescriptions.Add(<span>new </span><span>PropertyGroupDescription</span>(<span>"Age"</span>,<span>new  </span><span>AgeRangeConvert</span>()));
            }
            <span>else
            </span>{
            view.GroupDescriptions.Clear();
            }
登入後複製

一切搞定,享受成果吧:

WPF数据绑定(2 绑定列表数据Binding to List Data)

既然GroupDescripions是个集合类型,我们不妨看下面代码究竟是什么效果:

<span>            ICollectionView </span>view = GetView();
            <span>if </span>(view.GroupDescriptions.Count == 0)
            {
            view.GroupDescriptions.Add(<span>new </span><span>PropertyGroupDescription</span>(<span>"Age"</span>,<span>new  </span><span>AgeRangeConvert</span>()));
            view.GroupDescriptions.Add(<span>new </span><span>PropertyGroupDescription</span>(<span>"Age"</span>));
            }
            <span>else
            </span>{
            view.GroupDescriptions.Clear();
            }
登入後複製

运行如下:

WPF数据绑定(2 绑定列表数据Binding to List Data)

呵呵,这不正是有时你需要的效果吗?至于界面如何优化,模板如何定义更好看我们以后话题再
相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板