zoukankan      html  css  js  c++  java
  • WindowsPhone基础琐碎总结数据绑定(二)

     

        下面我们接着WindowsPhone基础琐碎总结-----数据绑定(一)继续探究数据绑定。
        四、集合对象的数据绑定
        通过上篇一个小例子我们基本了解了数据绑定原理,数值转换器的使用,数据绑定模式等相关知识,可是我们该如何把批量的数据绑定到UI呢?即绑定到数据集合对象(如ListBox等)。实现批量数据的绑定才是数据绑定的最大魅力所在。需要说明的是在集合对象的数据绑定中,绑定源可以是任意实现了枚举接口(IEnumerator)集合对象,而绑定目标一般是ItemControl控件类型的UI元素,本文我们将使用ListBox作为绑定的UI。
        在开始绑定集合前我们先了解下ItemControl控件,这类的控件有两个重要的属性一个是:ItemsSource和DisplayMemberPath,其实很好理解的,我们类比数据绑定(一)中介绍的绑定对象(Binding)的Source和Path属性。用法和道理基本一样我不在多说,不懂的参考我上一篇日志。
        1、显示单列的信息
        再动手做项目之前我们先考虑下需求,假如现在我们想显示一列学生姓名的信息,我们很快想到用ListBox控件,可是我们该如何把我们的道德姓名集合绑定到ListBox控件上呢?下面我们一步步介绍,不过为了为后面更复杂的绑定打基础,我们绑定一列班级信息到另一个页面。当然我们还是首先设计下UI,为了连贯性,我们继续在数据绑定(一)项目基础上继续。
        第一步:我们首先新建一个页面用来显示班级信息,页面名字为SingleColumnPage.xaml,界面上一个button和listbox控件,如下图:

    代码如下:

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <Button Content="显示班级名称信息" Height="72" HorizontalAlignment="Left" Margin="99,420,0,0" Name="buttonShowName" VerticalAlignment="Top" Width="260" Click="buttonShowName_Click" />
                <ListBox Height="349" HorizontalAlignment="Left" Margin="6,6,0,0" Name="listBox1" VerticalAlignment="Top" Width="444" />
            </Grid>


    然后我们主界面添加一个Button用于跳转,如下图:

    代码如下(我顺便加上了页面跳转的后台代码):

      private void button1_Click(object sender, RoutedEventArgs e)
            {
                NavigationService.Navigate(new Uri("/SingleColumnPage.xaml",UriKind.RelativeOrAbsolute));
            }

     


    第二步:下面我们开始后台的编写,既然要绑定班级名称信息,当然还要建立一个班级信息类StudentClass。代码如下:

       public class StudentClass
        {
            public string ClassName { set; get; }       
        }

     


    仅仅这一句就够举例用了,当然你可以添加更多需要的信息。
    下面我们单击显示班级名称,在后台写如下代码:
     

    private void buttonShowName_Click(object sender, RoutedEventArgs e)
            {
                ObservableCollection<StudentClass> Classes = new ObservableCollection<StudentClass>() 
                {
                    new StudentClass{ClassName=".Net1班"},
                    new StudentClass{ClassName=".Net2班"},
                    new StudentClass{ClassName=".Net3班"},
                    new StudentClass{ClassName=".Net2班"},
                    new StudentClass{ClassName="数据库1班"},
                    new StudentClass{ClassName="数据库2班"},
                    new StudentClass{ClassName="数据库3班"},
                    new StudentClass{ClassName="数据库4班"},
                };
                this.listBox1.ItemsSource = Classes;
                this.listBox1.DisplayMemberPath = "ClassName";    
            }

     

    现在你也许会问ObservableCollection是什么?有什么用?我们先做个插曲介绍下:如果你认真看过上篇博客数据绑定(一)一定还记得我们在介绍OneWay和TwoWay的时候让Student类实现了INotifyPropertyChanged接口。现在我要说明的是如果为一个集合实现OneWay和TwoWay的时候绑定的时候我们不仅仅要实现INotifyPropertyChanged接口,还得实现INotifyCollectionChanged接口,以便于将集合中的元素的更改通知到目标对象。这当然是繁琐的,有没有捷径呢?幸运的是SilverLight已经内置了一个实现了这两个接口的ObservableCollection<T>泛型类,位于using System.Collections.ObjectModel,命名空间下。一般情况下我们用这个类代替Collection<T>类即可实现更新通知。 了解这个类之后下面就好办了我们只要设定listBox控件的两个属性(ItemsSource 和)即可,代码已经在上面展示出来了。
    现在运行程序后转到显示单列数据页面并单击显示班级信息如下:

     2、绑定多列数据
        此时也许我们还想有这样一个需求,我想要显示多列,比如在一个页面中显示姓名,性别,年龄等,该怎么办呢?由于WindowsPhone没有像DataGridView类似的控件,所以我们必须使用自定义样式来实现我们想要的数据了。实现自定义样式需要设计数据模板这个知识了,我不打算做过多介绍本博文重在数据绑定,不能跑题,但是简单的理解就是一个简单的样式模板,每个学生信息都会用同样的样式,为了重用和布局的统一才抽象出了这个数据模板类:DataTemplate。新建一个学生信息页面,过程同显示班级信息页面, 我直接给AXML页面代码如下:

     <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <Button Content="显示学生信息" Height="72" HorizontalAlignment="Left" Margin="12,459,0,0" Name="buttonShowStudentsInfo" VerticalAlignment="Top" Width="417" Click="buttonShowStudentsInfo_Click" />
                <ListBox Height="422" Width="480" HorizontalAlignment="Left" Margin="-17,5,0,0" Name="listBox1" VerticalAlignment="Top" >             
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Height="120" HorizontalAlignment="Left" Width="480" VerticalAlignment="Top" Orientation="Horizontal">
                                <Image Stretch="Fill" Height="80" Width="120" Source="{Binding Path=Picture, Converter={StaticResource StringToBitMapImageKey}}"></Image>
                                <TextBlock Height="35"  Width="120"  Text="{Binding Path=Name}"></TextBlock>
                                <TextBlock Height="35"  Width="120"  Text="{Binding Path=Sex}"></TextBlock>
                                <TextBlock Height="35"  Width="120"  Text="{Binding Path=Birthday}"></TextBlock>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                
                </ListBox>
            </Grid>      

    上面的代码数据绑定方面我在第一篇博客都介绍过,应该都能够理解。下面我给出ShowStudentsInfoPage.xaml页面的后台代码如下:
    需要引入命名空间using System.Collections.ObjectModel;

    public partial class ShowStudentsInfoPage : PhoneApplicationPage
        {
            //构造学生信息
            ObservableCollection<Student> studentsInfo = new ObservableCollection<Student>() 
            {
                 new Student(){Picture="MM.jpg",Name="Marry",Sex="",Birthday="1988-5-1"},
                 new Student(){Picture="MM.jpg",Name="小红",Sex="",Birthday="1989-5-1"},
                 new Student(){Picture="GG.jpg",Name="GavinDream",Sex="",Birthday="1989-6-30"},
                 new Student(){Picture="GG.jpg",Name="小明",Sex="",Birthday="1989-8-1"},
            };
            public ShowStudentsInfoPage()
            {
                InitializeComponent();
            }   
            //绑定学生信息
            private void buttonShowStudentsInfo_Click(object sender, RoutedEventArgs e)
            {
                this.listBox1.ItemsSource = studentsInfo;         
    
            }
        }

     

    运行效果如下:

    解释一下,也就是说当我们选中Net1时候ListBox中显示Net1班的学生信息,当我们选中Net2时候ListBox中显示Net2班的学生信息;此刻你也许知道什么是分层数据显示了,不过你更容易想到我们可是使用事件解决此问题啊,是的,可以用事件来达到同样的效果,但是我们通常通过集合视图类(CollectionViewSource)可能会更方便的实现绑定。下面我具体介绍:
        首先了解下CollectionViewSource:是一个集合视图类,可以根据不同的筛选、排序条件建立一个集合对象的多个视图,其实就像关系型数据库中的同一张表中建立多个视图一样(如果还是理解不了,我们举个具体的例子:就像一个班级肯定是个学生的集合,学生可以根据不同条件分类,如按:男,女,20岁以上等条件分类,其实每一类得到的另一个学生集合就相当于一个视图。这些视图的源来自同一个集合就是这个班级)。下面具体介绍如何进行分层的数据绑定:
    第一步:设计UI,如上图,代码我会在设置绑定目标时贴出来       
    第二步:构造数据源对象
    既然还是数据绑定,那么还得先找到数据源,想把学生信息和班级名称联系起来,当然还得需要一个新的类,暂且起名为:ClassAndInfo吧,新建类,代码如下:

      public class ClassAndInfo
        {
            public string ClassName { set; get; }   
            public ObservableCollection<Student> studentInfo { set; get; }   
        }

     

    这个类是联系者,那么我们现在就可以开始构造一个数据源了,这个数据源必须存有学生信息和所在班级姓名,现在我们在新建一个类用于初始化数据源,类名为StudentsInfoList,如果把此类当做数据源集合必须继承一个泛型类ObservableCollection<T>,当然此次是继承
    ObservableCollection<ClassAndInfo>;因为数据源为ClassAndInfo类型;代码如下:

    public class StudentsInfoList:ObservableCollection<ClassAndInfo>
        {
            ClassAndInfo infolist1 = new ClassAndInfo()
            {
                ClassName = "Net1",
                studentInfo = new ObservableCollection<Student>() 
                    { 
                        new Student(){Picture="MM.jpg",Name="Marry",Sex="",Birthday="1988-5-1"},
                        new Student(){Picture="MM.jpg",Name="小红",Sex="",Birthday="1989-5-1"},
                        new Student(){Picture="GG.jpg",Name="GavinDream",Sex="",Birthday="1989-6-30"},
                        new Student(){Picture="GG.jpg",Name="小明",Sex="",Birthday="1989-8-1"},
                    }
            };
            ClassAndInfo infolist2 = new ClassAndInfo()
            {
                ClassName = "Net2",
                studentInfo = new ObservableCollection<Student>() 
                    { 
                        new Student(){Picture="MM.jpg",Name="张三",Sex="",Birthday="1988-5-1"},
                        new Student(){Picture="MM.jpg",Name="李四",Sex="",Birthday="1989-5-1"},
                        new Student(){Picture="GG.jpg",Name="王五",Sex="",Birthday="1989-6-30"},
                        new Student(){Picture="GG.jpg",Name="马六",Sex="",Birthday="1989-8-1"},
                    }
            };
            public StudentsInfoList()
            {
                //这两句是必须的,将数据对象加入当前类
                this.Add(infolist1);
                this.Add(infolist2);
            }
        }

     

    到此数据源解决了,那么就该数据绑定到UI了,xalm页面代码如下:

    <!--ContentPanel - 在此处放置其他内容-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <TextBlock Height="37" HorizontalAlignment="Left" Margin="12,20,0,0" Name="textBlock1" Text="请选择学生班级:" VerticalAlignment="Top" Width="163" />
                <ListBox Name="classname" DisplayMemberPath="ClassName" ItemsSource="{Binding Source={StaticResource StudentInfoListView}}" Margin="12,64,6,434"></ListBox>
                <TextBlock Height="37" HorizontalAlignment="Left" Margin="12,179,0,0" Name="textBlock2" Text="{Binding Source={StaticResource StudentInfoListView},Path=ClassName}" VerticalAlignment="Top" Width="72"  Foreground="Red"/>
                <TextBlock Height="37" HorizontalAlignment="Left" Margin="69,179,0,0" Name="textBlock3" Text="学生信息" VerticalAlignment="Top" Width="85"/>
                <ListBox ItemsSource="{Binding Path=studentInfo,Source={StaticResource StudentInfoListView}}" Height="379" HorizontalAlignment="Left" Margin="0,222,0,0" Name="listBox1" VerticalAlignment="Top" Width="450" ItemTemplate="{StaticResource ListDataTemplate}" />          
            </Grid>

    我需要给以上代码说明的是:ItemsSource="{Binding Source={StaticResource StudentInfoListView}}",里面引用的静态资源其实就是我们上面说的集合视图,我将它作为静态资源放在了xaml页面里,便于引用;静态资源代码如下:
      

    我们现在可以运行程序,效果如下:

    扩展:此刻我们也许会想到数据上下文DataContext,我们是否能够通过DataContext绑定到ListBox呢?我想是能的,那就试试吧:
    我们把 this.listBox1.ItemsSource = studentsInfo; 换成 this.listBox1.DataContext = studentsInfo;运行程序,没有像我想像的那样,绑定没有成功。经过调试和查找资料原来我们还得必须在Xaml页面指定listBox1的ItemsSource属性:ItemsSource="{Binding}",我认为其实这是再告诉编译器,我要进行数据绑定了,可是现在还没指定数据源(DataContext),一旦给我指定了DataContext我就去数据源中找应该绑定的属性,暂且这样理解吧。通过对比可以知道使用this.listBox1.ItemsSource = studentsInfo; 会更方便些。
       3、分层数据显示
       通过绑定学生信息我们可以实现对集合数据的绑定,并且还能够自定义UI样式,也许在项目中多数情况这基本上已经够用。但也可能会遇到这样一个需求:分层显示数据;这可能不好理解,那就拿此例子来说吧:我想把学生信息按班级分类,ListBox中显示不同班级的学生信息。也许还不太明白我直接上图吧:

    解释一下,也就是说当我们选中Net1时候ListBox中显示Net1班的学生信息,当我们选中Net2时候ListBox中显示Net2班的学生信息;此刻你也许知道什么是分层数据显示了,不过你更容易想到我们可是使用事件解决此问题啊,是的,可以用事件来达到同样的效果,但是我们通常通过集合视图类(CollectionViewSource)可能会更方便的实现绑定。下面我具体介绍:
        首先了解下CollectionViewSource:是一个集合视图类,可以根据不同的筛选、排序条件建立一个集合对象的多个视图,其实就像关系型数据库中的同一张表中建立多个视图一样(如果还是理解不了,我们举个具体的例子:就像一个班级肯定是个学生的集合,学生可以根据不同条件分类,如按:男,女,20岁以上等条件分类,其实每一类得到的另一个学生集合就相当于一个视图。这些视图的源来自同一个集合就是这个班级)。下面具体介绍如何进行分层的数据绑定:
    第一步:设计UI,如上图,代码我会在设置绑定目标时贴出来       
    第二步:构造数据源对象
    既然还是数据绑定,那么还得先找到数据源,想把学生信息和班级名称联系起来,当然还得需要一个新的类,暂且起名为:ClassAndInfo吧,新建类,代码如下:

      public class ClassAndInfo
        {
            public string ClassName { set; get; }   
            public ObservableCollection<Student> studentInfo { set; get; }   
        }

     


    这个类是联系者,那么我们现在就可以开始构造一个数据源了,这个数据源必须存有学生信息和所在班级姓名,现在我们在新建一个类用于初始化数据源,类名为StudentsInfoList,如果把此类当做数据源集合必须继承一个泛型类ObservableCollection<T>,当然此次是继承
    ObservableCollection<ClassAndInfo>;因为数据源为ClassAndInfo类型;代码如下:

    public class StudentsInfoList:ObservableCollection<ClassAndInfo>
        {
            ClassAndInfo infolist1 = new ClassAndInfo()
            {
                ClassName = "Net1",
                studentInfo = new ObservableCollection<Student>() 
                    { 
                        new Student(){Picture="MM.jpg",Name="Marry",Sex="",Birthday="1988-5-1"},
                        new Student(){Picture="MM.jpg",Name="小红",Sex="",Birthday="1989-5-1"},
                        new Student(){Picture="GG.jpg",Name="GavinDream",Sex="",Birthday="1989-6-30"},
                        new Student(){Picture="GG.jpg",Name="小明",Sex="",Birthday="1989-8-1"},
                    }
            };
            ClassAndInfo infolist2 = new ClassAndInfo()
            {
                ClassName = "Net2",
                studentInfo = new ObservableCollection<Student>() 
                    { 
                        new Student(){Picture="MM.jpg",Name="张三",Sex="",Birthday="1988-5-1"},
                        new Student(){Picture="MM.jpg",Name="李四",Sex="",Birthday="1989-5-1"},
                        new Student(){Picture="GG.jpg",Name="王五",Sex="",Birthday="1989-6-30"},
                        new Student(){Picture="GG.jpg",Name="马六",Sex="",Birthday="1989-8-1"},
                    }
            };
            public StudentsInfoList()
            {
                //这两句是必须的,将数据对象加入当前类
                this.Add(infolist1);
                this.Add(infolist2);
            }
        }

     

    到此数据源解决了,那么就该数据绑定到UI了,xalm页面代码如下:

    <!--ContentPanel - 在此处放置其他内容-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <TextBlock Height="37" HorizontalAlignment="Left" Margin="12,20,0,0" Name="textBlock1" Text="请选择学生班级:" VerticalAlignment="Top" Width="163" />
                <ListBox Name="classname" DisplayMemberPath="ClassName" ItemsSource="{Binding Source={StaticResource StudentInfoListView}}" Margin="12,64,6,434"></ListBox>
                <TextBlock Height="37" HorizontalAlignment="Left" Margin="12,179,0,0" Name="textBlock2" Text="{Binding Source={StaticResource StudentInfoListView},Path=ClassName}" VerticalAlignment="Top" Width="72"  Foreground="Red"/>
                <TextBlock Height="37" HorizontalAlignment="Left" Margin="69,179,0,0" Name="textBlock3" Text="学生信息" VerticalAlignment="Top" Width="85"/>
                <ListBox ItemsSource="{Binding Path=studentInfo,Source={StaticResource StudentInfoListView}}" Height="379" HorizontalAlignment="Left" Margin="0,222,0,0" Name="listBox1" VerticalAlignment="Top" Width="450" ItemTemplate="{StaticResource ListDataTemplate}" />          
            </Grid>

     

    我需要给以上代码说明的是:ItemsSource="{Binding Source={StaticResource StudentInfoListView}}",里面引用的静态资源其实就是我们上面说的集合视图,我将它作为静态资源放在了xaml页面里,便于引用;静态资源代码如下:

      <!--定义页面资源-->
        <phone:PhoneApplicationPage.Resources>
            <local:StudentsInfoList x:Key="StudentInfoList"/>
            <CollectionViewSource x:Key="StudentInfoListView" Source="{StaticResource StudentInfoList}"></CollectionViewSource>
            <DataTemplate x:Key="ListDataTemplate">
                <StackPanel Height="120" HorizontalAlignment="Left" Width="480" VerticalAlignment="Top" Orientation="Horizontal">
                    <Image Stretch="Fill" Height="80" Width="120" Source="{Binding Path=Picture, Converter={StaticResource StringToBitMapImageKey}}"></Image>
                    <TextBlock Height="35"  Width="120"  Text="{Binding Path=Name}"></TextBlock>
                    <TextBlock Height="35"  Width="120"  Text="{Binding Path=Sex}"></TextBlock>
                    <TextBlock Height="35"  Width="120"  Text="{Binding Path=Birthday}"></TextBlock>
                </StackPanel>
            </DataTemplate>
        </phone:PhoneApplicationPage.Resources>

    我们现在可以运行程序,效果如下:

    点击Net2

    总结:利用三天的闲暇时间,终于把数据绑定(二)更新完了,对于windowsphone7自己也是刚刚接触,所写的仅仅是自己的琐碎总结加入了自己的理解,文中的不足之处还请见谅,望各位园友批评指出。

    ---------------------------------------------------------------------------------------------------------------------------------------------

    作者:GavinDream(GavinDream主页 博客园
    出处:http://www.cnblogs.com/fuchongjundream/
    任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问或者授权方面的协商,请发邮件给我 或者 留言

  • 相关阅读:
    Codeforces Round #538 (Div. 2) F. Please, another Queries on Array?
    2021 ICPC济南 J Determinant
    牛客小白月赛43 F 全体集合
    The 2021 ICPC Asia Regionals Online Contest (II) L Euler Function
    C++文件操作详解
    利用VC实现图像的特殊显示效果 小楼machine
    Mixed mode assembly is built against version 'v2.0.50727' 解决方案 小楼machine
    如何在对话框资源从一个项目导入到另一个项目使用 Visual c + +.net 或 Visual c + + 2005 小楼machine
    灰度图像阈值化分割常见方法总结及VC实现 小楼machine
    Visual C++多媒体设计及图形、图像处理 小楼machine
  • 原文地址:https://www.cnblogs.com/fuchongjundream/p/2487251.html
Copyright © 2011-2022 走看看