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用于数据有效性校验的关卡

  • 相关阅读:
    hdu 3033 I love sneakers!
    poj 1742 Coins
    poj 1276 Cash Machine
    hdu 1114 Piggy-Bank
    poj 1293 Duty Free Shop
    hdu 1203 I NEED A OFFER!
    hdu 2546 饭卡
    树的直径
    CF 337D Book of Evil
    ST表
  • 原文地址:https://www.cnblogs.com/chenyongblog/p/3498473.html
Copyright © 2011-2022 走看看