热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

WPF数据绑定(2绑定列表数据BindingtoListData)

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

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

(读完此系列WPF和Silverlight的数据绑定问题你就轻松搞定

1 Binding to List Data

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

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

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

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

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

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

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

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

private void btnNext_Click(object sender, RoutedEventArgs e)
            {
            People people = (People)this.FindResource("Family");
            txtName.Text = people[1].Name;
            txtAge.Text = people[1].Age.ToString();
            }

1.1当前项Current Item

取得当前项

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

还是代码说明比较简洁:

People people = (People)this.FindResource("Family");
            ICollectionView view = CollectionViewSource.GetDefaultView(people);
            Person peron = (Person)view.CurrentItem;

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

导航当前项

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

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

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

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

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

代码示例也许更易理解:

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

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

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

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

1.5 列表改变List Changes

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

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

namespace System.Collections.Specialized
            {
            public interface INotifyCollectionChanged
            {
            event NotifyCollectionChangedEventHandler CollectionChanged;
            }
            }

namespace System.Collections.ObjectModel
            {
            public class ObservableCollection : Collection, INotifyCollectionChanged, INotifyPropertyChanged
            {
            ...
            }
            }

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

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

//People类
            class People : ObservableCollection<Person>
            {
            }

1.6 排序Sorting

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

       private void btnSort_Click(object sender, RoutedEventArgs e)
            {
            ICollectionView view = GetView();
            if (view.SortDescriptions.Count == 0)
            {
            view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
            view.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Descending));
            }
            else
            {
            view.SortDescriptions.Clear();
            }
            }

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

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

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

使用代码如下:

       private void btnSort_Click(object sender, RoutedEventArgs e)
            {
            ListCollectionView view = (ListCollectionView)GetView();
            if (view.CustomSort == null)
            {
            view.CustomSort = new PersonSorter();
            }
            else
            {
            view.CustomSort = null;
            }
            }

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

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

1.8 过滤 Filter

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

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

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

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

          ICollectionView view = GetView();
            if (view.GroupDescriptions.Count == 0)
            {
            view.GroupDescriptions.Add(new PropertyGroupDescription("Age"));
            }
            else
            {
            view.GroupDescriptions.Clear();
            }

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

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

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

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

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

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

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

简单调整前面分组代码:

           ICollectionView view = GetView();
            if (view.GroupDescriptions.Count == 0)
            {
            view.GroupDescriptions.Add(new PropertyGroupDescription("Age",new  AgeRangeConvert()));
            }
            else
            {
            view.GroupDescriptions.Clear();
            }

一切搞定,享受成果吧:

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

            ICollectionView view = GetView();
            if (view.GroupDescriptions.Count == 0)
            {
            view.GroupDescriptions.Add(new PropertyGroupDescription("Age",new  AgeRangeConvert()));
            view.GroupDescriptions.Add(new PropertyGroupDescription("Age"));
            }
            else
            {
            view.GroupDescriptions.Clear();
            }

运行如下:

呵呵,这不正是有时你需要的效果吗?至于界面如何优化,模板如何定义更好看我们以后话题再
推荐阅读
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 题库来源:安全生产模拟考试一点通公众号小程序G3锅炉水处理报名考试是安全生产模拟考试一点通生成的,G3锅炉水处理证模拟考试题库是根据G3锅炉水处理最新 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • Ralph的Kubernetes进阶之旅:集群架构与对象解析
    本文深入探讨了Kubernetes集群的架构和核心对象,详细介绍了Pod、Service、Volume等基本组件,以及更高层次的抽象如Deployment、StatefulSet等,帮助读者全面理解Kubernetes的工作原理。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 本文详细探讨了Java中StringBuffer类在不同情况下的扩容规则,包括空参构造、带初始字符串和指定初始容量的构造方法。通过实例代码和理论分析,帮助读者更好地理解StringBuffer的内部工作原理。 ... [详细]
  • 本文探讨了领域驱动设计(DDD)的核心概念、应用场景及其实现方式,详细介绍了其在企业级软件开发中的优势和挑战。通过对比事务脚本与领域模型,展示了DDD如何提升系统的可维护性和扩展性。 ... [详细]
  • 深入了解 Windows 窗体中的 SplitContainer 控件
    SplitContainer 控件是 Windows 窗体中的一种复合控件,由两个可调整大小的面板和一个可移动的拆分条组成。本文将详细介绍其功能、属性以及如何通过编程方式创建复杂的用户界面。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 本文探讨了在Linux系统上使用Docker时,通过volume将主机上的HTML5文件挂载到容器内部指定目录时遇到的403错误,并提供了解决方案和详细的操作步骤。 ... [详细]
  • 作为一名专业的Web前端工程师,掌握HTML和CSS的命名规范是至关重要的。良好的命名习惯不仅有助于提高代码的可读性和维护性,还能促进团队协作。本文将详细介绍Web前端开发中常用的HTML和CSS命名规范,并提供实用的建议。 ... [详细]
  • 本文探讨了在 ASP.NET MVC 5 中实现松耦合组件的方法。通过分离关注点,应用程序的各个组件可以更加独立且易于维护和测试。文中详细介绍了依赖项注入(DI)及其在实现松耦合中的作用。 ... [详细]
author-avatar
男人邦121121121
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有