zoukankan      html  css  js  c++  java
  • 14、数据绑定相关例子

    1、把普通CLR类型单个对象指定为Source:包括.NET Framework自带类型的对象和用户自定义类型的对象。

    如果类型实现了INotifyPropertyChanged接口,则可通过在属性的set语句里激发PropertyChanged事件来通知Binding数据已被更新。

    using System.ComponentModel;
    
    namespace _SampleDataBinding
    {
        class Person:INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            private string _personName= string.Empty;
    
            public string PersonName 
            {
                get { return this._personName; }
                set { this._personName = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged.Invoke(this,new PropertyChangedEventArgs(PersonName));
                    }
                }
            }
        }
    }
    <StackPanel>
            <TextBox Name="TxtTest1" Text="{Binding Source={StaticResource MyPerson}, Path=PersonName}"></TextBox>
            <Button Name="BtnTest" Height="36" Click="BtnTest_OnClick">修改下试试</Button>
    </StackPanel>
            private void BtnTest_OnClick(object sender, RoutedEventArgs e)
            {
                Person per=new Person();
                per.PersonName = "我修改名字了,叫麦克";
            }

    2、把普通CLR集合类型对象指定为Source:包括数组、List<T>、ObservableCollection<T>等集合类型。

        class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
        }
        <StackPanel Background="LightBlue">
            <TextBlock Text="学号:" FontWeight="Bold" Margin="5" FontSize="16"></TextBlock>
            <TextBox x:Name="TxtBoxId" Margin="5" Height="36"></TextBox>
            <TextBlock Text="学生集合:" FontSize="16" FontWeight="Bold" Margin="5"></TextBlock>
            <ListBox x:Name="ListBoxStudents" Height="195" Margin="5">
            </ListBox>
        </StackPanel>
                //准备数据源
                List<Student> stuList =new List<Student> ( )
                {
                    new Student(){Id = 001,Name = "Apple",Age = 12},
                    new Student(){Id = 002,Name = "Banana",Age = 13},
                    new Student(){Id = 003,Name = "Cocoa",Age = 14},
                    new Student(){Id = 004,Name = "Dog",Age = 15},
                    new Student(){Id = 005,Name = "Func",Age = 16},
                    new Student(){Id = 006,Name = "Great",Age = 17}
                };
                //为ListBox设置Binding
                this.ListBoxStudents.ItemsSource = stuList;
                this.ListBoxStudents.DisplayMemberPath = "Name";
                //为TextBox设置Binding
                Binding binding=new Binding("SelectedItem.Id"){Source = this.ListBoxStudents};
                this.TxtBoxId.SetBinding(TextBox.TextProperty, binding);

    如果将绑定代码写在XAML中该怎么写呢?

    <TextBox x:Name="TxtBoxId"  Text="{Binding ElementName=ListBoxStudents,Path=SelectedItem.Id}"></TextBox>

    在写Path的时候SelectedItem.Id,其中.Id是不提示的,需要硬写上去。

     想试试直接在XAML中绑定,然后搞了半天没成功,请教了猥琐猫之后他给了个解决方案,下面是代码

        public class Student
        {
            public int StudentNum { get; set; }
            public string StudentName { get; set; }
            public int StudentAge { get; set; }
        }
        public class Data
        {
            private List<Student> _studentsList; 
            public List<Student> StudentsList
            {
                get { return _studentsList; } 
                set { _studentsList = value; }
            }
        }
        {
            public Data myData;
            private List<Student> studentsList; 
            public MainWindow ( )
            {
                InitializeComponent ( );
                myData=new Data();
                //准备数据源
    
                studentsList =new List<Student> ( )
                {
                    new Student(){StudentNum = 001,StudentName  = "Apple",StudentAge = 12},
                    new Student(){StudentNum = 002,StudentName = "Banana",StudentAge = 13},
                    new Student(){StudentNum = 003,StudentName = "Cocoa",StudentAge = 14},
                    new Student(){StudentNum = 004,StudentName = "Dog",StudentAge = 15},
                    new Student(){StudentNum = 005,StudentName = "Func",StudentAge = 16},
                    new Student(){StudentNum = 006,StudentName = "Great",StudentAge = 17}
                };
                myData.StudentsList = studentsList;
                this.DataContext = myData;
            }

     再写个例子试试

            private List<Student> stuList; 
            public MainWindow ( )
            {
                InitializeComponent ( );
                stuList=new List<Student>()
                    {
                        new Student(){StudentId = 001,StudentName = "张三",StudentAge = 12},
                        new Student(){StudentId = 002,StudentName = "李四",StudentAge = 13},
                        new Student(){StudentId = 003,StudentName = "王五",StudentAge = 14},
                        new Student(){StudentId = 004,StudentName = "赵六",StudentAge = 15},
                        new Student(){StudentId = 005,StudentName = "陈七",StudentAge = 16}
                    };
                this.listBoxStudents.ItemsSource = stuList;
            }
            <ListBox x:Name="listBoxStudents" Height="300" Margin="5" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Path=StudentId}" Width="30"></TextBlock>
                            <TextBlock Text="{Binding Path=StudentName}" Width="60"></TextBlock>
                            <TextBlock Text="{Binding Path=StudentAge}" Width="30"></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

    如果上面这个例子中又来了几条数据咋办啊?WPF给出的解决方案是:在使用集合类型作为列表空间的ItemSource时一般会考虑使用ObservableCollection<T>

    来替换List<T>,因为ObservableCollection<T>实现了INotifyCollectionChanged和INotifyPropertyChanged接口,能够把集合的变化立刻通知显示它的

    列表控件,该百脑汇立刻显示出来。

                private ObservableCollection<Student> newStuList;
    
                newStuList=new ObservableCollection<Student>()
                    {
                        new Student(){StudentId = 001,StudentName = "张三",StudentAge = 12},
                        new Student(){StudentId = 002,StudentName = "李四",StudentAge = 13},
                        new Student(){StudentId = 003,StudentName = "王五",StudentAge = 14},
                        new Student(){StudentId = 004,StudentName = "赵六",StudentAge = 15},
                        new Student(){StudentId = 005,StudentName = "陈七",StudentAge = 16}
                    };
    
                this.listBoxStudents.ItemsSource = newStuList;
    
    
            private void BtnTest_OnClick(object sender, RoutedEventArgs e)
            {
                newStuList.Add(new Student(){StudentId = 006,StudentName = "新添加的",StudentAge = 17});
    
            }

    3、将ElementName指定为Source

            <TextBox Name="TxtBox" BorderBrush="DeepSkyBlue" Height="35" Margin="5" 
              Text
    ="{Binding ElementName=SliderTest,Path=Value,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox> <Slider Name="SliderTest" Margin="5" BorderBrush="DimGray" Maximum="100" Minimum="0"></Slider>

     Mode表示数据流动的方向,其值TwoWay说明数据是双向流动的,Slider控件的值能够更新到TextBox,TextBox上的值也能够更新到Slider上,实现这个功能需要修改

    UpdateSourceTrigger属性的值,因为TextBox的该属性值默认为Default也就是LostFocus,当失去焦点之后才发生变化。

    4、没有Path的绑定

        <StackPanel>
            <StackPanel.Resources>
                <sys:String x:Key="myString">没有Path的绑定,静态资源</sys:String>
            </StackPanel.Resources>
            <TextBlock Name="TextBlockTest" Text="{Binding Source={StaticResource myString} }"></TextBlock>
        </StackPanel>

    C#中的等效代码

                string a = "dafagagdfgghh";
                this.TextBoxTest.SetBinding(TextBox.TextProperty, new Binding(".") {Source = a});

    前面的例子大多是把单个CLR类型对象指定为Binding的Source,方法有两种-把Banding.Source属性或把对象的Name赋值给Binding.ElementName。

    5、没有Source的绑定-使用DataContext作为Binding的源

     DataContext属性被定义在FrameworkElement类里,这个类是WPF控件的基类,这意味着WPF空间(包括容器控件)都具备这种属性。如前所述,WPF的UI布局是树形结构,这棵树的每个节点都有DataContext。

    当一个Binding只知道自己的Path而不知道自己的Source时,它会沿着UI元素树一路向树的根部找过去,每路过一个结点就要看看这个结点的DataContext是否具有Path所指定的属性。如果有就把这个对象作为自己的Source;如果没有,那就继续找下去;如果到了树的根部还没有找到,那么这个Binding就没有Source,因而也不会得到数据。

    eg1:

        <Grid DataContext="你好">
            <Grid>
                <StackPanel>
                    <Button x:Name="BtnTest" Content="点击试试" Click="BtnTest_OnClick"></Button>
                </StackPanel>
            </Grid>
        </Grid>
            private void BtnTest_OnClick(object sender, RoutedEventArgs e)
            {
                MessageBox.Show(BtnTest.DataContext.ToString());
            }

    eg2:

        <Grid DataContext="你好">
            <Grid>
                <StackPanel>
                    <Button x:Name="BtnTest" Content="点击试试" Click="BtnTest_OnClick"></Button>
                    <TextBox x:Name="TextBoxtTest" Text="{Binding Path=.}"></TextBox>
                </StackPanel>
            </Grid>
        </Grid>

    eg3:

        public partial class Student
        {
            public int StuId { get; set; }
            public string StuName { get; set; }
            public int StuAge { get; set; }
        }
        <StackPanel>
            <StackPanel.DataContext>
               <local:Student StuId="001" StuName="张三" StuAge="100"></local:Student>
            </StackPanel.DataContext>
            <TextBox Text="{Binding StuId}"></TextBox>
            <TextBox Text="{Binding StuName}"></TextBox>
            <TextBox Text="{Binding StuAge}"></TextBox>
        </StackPanel>

    eg4:MVVM模式解决 小灰猫提供的解决方案

        class StudentViewModel
        {
            public Student stu { get; set; }
    
            public StudentViewModel()
            {
                stu=new Student()
                    {
                        StuId = 2,
                        StuName = "张三",
                        StuAge = 100
                    };
            }
        }
        public partial class MainWindow : Window
        {
            public MainWindow ( )
            {
                InitializeComponent ( );
                this.DataContext = new StudentViewModel();
            }
        }
        <StackPanel DataContext="{Binding stu}">
            <TextBox Text="{Binding StuId}"></TextBox>
            <TextBox Text="{Binding StuName}"></TextBox>
            <TextBox Text="{Binding StuAge}"></TextBox>
        </StackPanel>

     6、使用XML数据作为Binding的数据源

        <Window.Resources>
            <XmlDataProvider x:Key="xdp" XPath="FileSystem/Folder">
                <x:XData>
                    <FileSystem xmlns="">
                        <Folder Name="A">
                            <Folder Name="BooksA">
                                <Folder Name="Programming">
                                    <Folder Name="Windows">
                                        <Folder Name="WCF"/>
                                        <Folder Name="MFC"/>
                                        <Folder Name="Delphi"/>
                                    </Folder>
                                </Folder>
                                <Folder Name="Tools">
                                    <Folder Name="Development"/>
                                    <Folder Name="Designment"/>
                                    <Folder Name="Players"/>
                                </Folder>
                                <Folder Name="Tools">
                                    <Folder Name="Development"/>
                                    <Folder Name="Designment"/>
                                    <Folder Name="Players"/>
                                </Folder>
                            </Folder>
                            <Folder Name="BooksB">
                                <Folder Name="Programming">
                                    <Folder Name="Windows">
                                        <Folder Name="WCF"/>
                                        <Folder Name="MFC"/>
                                        <Folder Name="Delphi"/>
                                    </Folder>
                                </Folder>
                                <Folder Name="Tools">
                                    <Folder Name="Development"/>
                                    <Folder Name="Designment"/>
                                    <Folder Name="Players"/>
                                </Folder>
                                <Folder Name="Tools">
                                    <Folder Name="Development"/>
                                    <Folder Name="Designment"/>
                                    <Folder Name="Players"/>
                                </Folder>
                            </Folder>
                        </Folder>
                    </FileSystem>
                </x:XData>
            </XmlDataProvider>
        </Window.Resources>
        <Grid>
            <TreeView ItemsSource="{Binding Source={StaticResource xdp}}">
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding XPath=Folder}">
                        <TextBlock Text="{Binding XPath=@Name}"></TextBlock>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
        </Grid>

    如果把XmlDataProvider直接写在XAML代码里,那么它的XML数据需要放在<x:Data>...</X:Data>标签里。

    如果将XML文件单独写,该如何?

    <?xml version="1.0" encoding="utf-8" ?>
    <StudentList>
      <Student Id="1">
        <Name>Trim</Name>
      </Student>
      <Student Id="2">
        <Name>Tom</Name>
      </Student>
      <Student Id="3">
        <Name>Jim</Name>
      </Student>
      <Student Id="4">
        <Name>Aim</Name>
      </Student>
    </StudentList>
        <StackPanel Background="DeepSkyBlue">
            <ListView x:Name="listViewTest" Height="200">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding XPath=@Id}"></GridViewColumn>
                        <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding XPath=Name}"></GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
            <Button Height="36" Click="ButtonBase_OnClick">XML作为绑定源</Button>
            <Button Height="36" Margin="0,5,0,0" Name="BtnTest" Click="BtnTest_OnClick">新的写法</Button>
        </StackPanel>
            private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
            {
                XmlDocument doc=new XmlDocument();
                doc.Load(@"./StudentsData.xml");
                XmlDataProvider xdp=new XmlDataProvider();
                xdp.Document = doc;
                xdp.XPath = @"/StudentList/Student";
    
                this.listViewTest.DataContext = xdp;
                this.listViewTest.SetBinding(ListView.ItemsSourceProperty, new Binding());
            }
    
            private void BtnTest_OnClick(object sender, RoutedEventArgs e)
            {
                XmlDataProvider xdp=new XmlDataProvider();
                xdp.Source = new Uri ( @"E:C#WPF数据绑定练习8使用XML数据作为Binding的源inDebugStudentsData.xml" );
                xdp.XPath = @"/StudentList/Student";
    
                this.listViewTest.DataContext = xdp;
                this.listViewTest.SetBinding(ListView.ItemsSourceProperty, new Binding());
            }

    两种不同的读取方式

    7、使用LINQ检索结果作为Binding的源

            <ListView x:Name="listViewStudents" Height="143" Margin="5">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Id" Width="60" DisplayMemberBinding="{Binding Id}"></GridViewColumn>
                        <GridViewColumn Header="Name" Width="100" DisplayMemberBinding="{Binding Name}"></GridViewColumn>
                        <GridViewColumn Header="Age" Width="80" DisplayMemberBinding="{Binding Age}"></GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
            private void BtnTest_OnClick(object sender, RoutedEventArgs e)
            {
                List<Student> stuList=new List<Student>()
                    {
                        new Student(){Id = 0,Name = "Tim",Age=10},
                        new Student(){Id = 1,Name = "Tom",Age = 11},
                        new Student(){Id = 2,Name = "Tony",Age = 12},
                        new Student(){Id = 3,Name = "Jim",Age = 13}
                    };
                this.listViewStudents.ItemsSource = from student in stuList
                                                    where student.Name.StartsWith("T")
                                                    select student;
    
            }

     8、使用ObjectDataProvider对象作为BindingSource:就是将对象作为数据源提供给Binding

    理想的情况下,上游程序员把类ishejihao、使用属性把数据暴露出来,下游程序员把这些类的实例作为Binding的Source、把属性作为Binding的Path来消费这些类。但是很难保证一个类idea所有数据都能使用属性来暴露,比如我们需要的数据可能是方法的返回值。而重新设计底层类的风险和成本会比较高,况且黑盒引用类库的情况下我们也不可能更改已经编译好的类,这时就要使用ObjectDataProvider来包装作为Binding的源数据对象了。 

        class Calculator
        {
            public string Add(string str1, string str2)
            {
                double x,y,z = 0;
                if (double.TryParse(str1, out x) && double.TryParse(str2, out y))
                {
                    z = x + y;
                    return z.ToString();
                }
                else
                {
                    return "Inpurt Error!";
                }
            }
        }
            private void BtnTest_OnClick(object sender, RoutedEventArgs e)
            {
                ObjectDataProvider odp=new ObjectDataProvider();
                odp.ObjectInstance = new Calculator();
                odp.MethodName = "Add";
                odp.MethodParameters.Add("100");
                odp.MethodParameters.Add("200");
                MessageBox.Show(odp.Data.ToString());
            }

    在XAML中实现

        public partial class MainWindow : Window
        {
            public MainWindow ( )
            {
                InitializeComponent ( );
                this.SetBinding();
            }
    
            private void SetBinding()
            {
                //创建并配置ObjectDataProvider对象
                ObjectDataProvider odp=new ObjectDataProvider();
                odp.ObjectInstance = new Calculator();
                odp.MethodName = "Add";
                odp.MethodParameters.Add("10");
                odp.MethodParameters.Add("10");
    
                //以ObjectDataProvider对象为Source创建Binding
                Binding bindingToStr1=new Binding("MethodParameters[0]")
                    {
                        Source = odp,
                        BindsDirectlyToSource=true,
                        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                    };
    
                Binding bindingToStr2=new Binding("MethodParameters[1]")
                    {
                        Source = odp,
                        BindsDirectlyToSource = true,
                        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                    };
    
                Binding bindingToResult=new Binding("."){Source = odp};
    
                //将Binding关联到UI元素上
                this.TextBoxStr1.SetBinding(TextBox.TextProperty, bindingToStr1);
                this.TextBoxStr2.SetBinding(TextBox.TextProperty, bindingToStr2);
                this.TextBoxResult.SetBinding(TextBox.TextProperty, bindingToResult);
            }

    9、绑定对数据的转换和校验
    Binding的作用就是在Source与Target之间建立桥梁,在这座桥上可以设置关卡对数据的有效性进行校验,当Binding两端要求使用不同的数据类型时,我们还可以为数据设置转换器。

    Binding用于数据有效性校验的关卡

  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
  • 原文地址:https://www.cnblogs.com/chenyongblog/p/3498473.html
Copyright © 2011-2022 走看看