• Binding基础 文摘


    简要

      • Binding基础
      • Binding源与路径
      • 列举Binding的源

    Binding基础

    从Coding中看Binding的基础。

    先定义一个Student类:

    public class Student : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
     
        private string name;
        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                name = value;
                if (PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
                }
            }
        }
    }
    XAML设计:
    <StackPanel Height="70">
        <TextBox x:Name="textBoxName" BorderBrush="Black" Margin="5"></TextBox>
        <Button Content="Add Name" Margin="5" Click="Button_Click"></Button>
    </StackPanel>
    后台部分:
    public partial class MainWindow : Window
    {
        Student stu;
     
        public MainWindow()
        {
            InitializeComponent();
            stu = new Student();
            Binding binding = new Binding();
            binding.Source = stu;
            binding.Path = new PropertyPath("Name");
     
            BindingOperations.SetBinding(this.textBoxName, TextBox.TextProperty, binding);
        }
     
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            stu.Name += "LiLin";
        }
    }

    在这个例子中,binding的源是stu,binding的路径是Name,既UI关心的那个属性。

    首先,定义的Student实现了INotifyPropertyChanged接口,并在Name的set中激发PropertyChanged事件,这是为了是Binding机制能自动监听,并会通知Binding目标端的UI现实新的值。

    在后台代码中,Binding部分是先声明Binding类型变量并创建实例,然后指定源与路径,最后使用BindingOperations.SetBinding(…)来实现数据源与目标的连接。

    实际中,不需要这么麻烦地实现Binding,因为TextBox继承自FrameworkElement,对BindingOperations.SetBinding(…)进行了封装,提供SetBinding方法:

    public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding)
    {
        return BindingOperations.SetBinding(this, dp, binding);
    }
    使用SetBinding可以简化为:
    InitializeComponent();
    stu = new Student();
    this.textBoxName.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = stu });

    Binding的源与路径

    Binding的源只要是一个对象,且拥有公开的属性。可以是实现了INotifyPropertyChanged接口的自定义类、控件、集合、XML…

    把控件作为Binding的源:

    <StackPanel Height="70">
        <TextBox x:Name="textBoxValue" BorderBrush="Black" Margin="5" Text="{Binding Path=Value, ElementName=slider, UpdateSourceTrigger=PropertyChanged}"></TextBox>
        <Slider x:Name="slider" Maximum="100" Minimum="0" Margin="5"></Slider>
    </StackPanel>

    控制Binding的方向和数据更新触发方式:

    控制Binding数据流向的属性是Mode,枚举。可以取值为:TwoWay、OneWay、OnTime、OneWayToSource、Default。

    控制数据更新触发方式的属性是UpdateSourceTrigger,类型是UpdateSourceTrigger枚举,可以取值为:PropertyChanged、LostFocus、Explicit和Default。

    Binding的路径:

    Binding的路径是指示Binding关注的属性。

    为Binding指定源的几种方法:

    1. 把普通的CLR类型单一对象指定为Source:该类型需实现INotifyPropertyChanged接口,并通过属性的Set语句里激发PropertyChanged事件;
    2. 把普通的CLR集合类型对象指定为源:包含数组、List<T>、ObservableCollection<T>等集合类型;
    3. 把ADO.NET数据对象指定为源:有DataTable和DataView等对象;
    4. 使用XmlDataProvider把XML数据指定为Source;
    5. 把以来对象指定为源;
    6. 把容器的DataContext指定为源;
    7. 通过ElementName指定源:用于XAML中;
    8. 通过Binding的RelativeSource属性相对指定Source:当控件需要关注自己的、自己容器的或者自己内部元素的某个值就需要使用到这个属性;
    9. 把ObjectDataProvider对象指定为源;
    10. 把使用LINQ检索得到的数据对象作为源。

      使用DataContext作为Binding的源:

      DataContext是定义在WPF控件基类FrameworkElement中,因此所有WPF控件都有这个属性。

      简单例子:

      <Window x:Class="BindBasicTest.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:BindBasicTest"
              Title="MainWindow" Height="150" Width="230">
          <StackPanel Height="100">
              <StackPanel.DataContext>
                  <local:Student Id="100" Name="LiLin" Age="18"></local:Student>
              </StackPanel.DataContext>
              <TextBox Text="{Binding Path=Id}" Margin="5"></TextBox>
              <TextBox Text="{Binding Path=Name}" Margin="5"></TextBox>
              <TextBox Text="{Binding Path=Age}" Margin="5"></TextBox>
          </StackPanel>
      </Window>

      使用集合对象作为列表控件的ItemsSource:

      列表控件都是派生自ItemsControl类,则都继承了ItemsSource这个属性。ItemsSource属性可以接受一个IEnumerable接口的派生类。只要为ItemsControl对象设置ItemsSource属性值,ItemsSource就会自动迭代其中的数据。

      例子:

      XAML设计:

      StackPanel Background="LightBlue">
          <TextBlock Text="Student ID" FontWeight="Bold" Margin="5"></TextBlock>
          <TextBox x:Name="txtBoxId" Margin="5"></TextBox>
          <TextBlock Text="Student List" FontWeight="Bold" Margin="5"></TextBlock>
          <ListBox x:Name="listBoxStudent" Height="80"></ListBox>
      </StackPanel>
      后台代码:
      public MainWindow()
      {
          InitializeComponent();
       
          List<Student> stu_list = new List<Student>()
          {
              new Student(){Id=0,Name="LiLin",Age=18},
              new Student(){Id=1,Name="LinLi",Age=20},
              new Student(){Id=2,Name="LLiin",Age=24},
              new Student(){Id=3,Name="Tom",Age=27},
              new Student(){Id=4,Name="Tim",Age=19},
              new Student(){Id=5,Name="Luke",Age=23},
          };
       
          this.listBoxStudent.ItemsSource = stu_list;
          this.listBoxStudent.DisplayMemberPath = "Name";
       
          this.txtBoxId.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = this.listBoxStudent });
       
      }
      this.listBoxStudent.DisplayMemberPath = "Name";这是设置listbox显示字段,如果要显示多个或者全部字段呢。这就要使用到类型为DataTemplate的ItemTemplate属性(继承自ItemsControl类),通俗的说是换衣服。在XAML中修改代码,并把this.listBoxStudent.DisplayMemberPath = "Name";删除:
      <ListBox x:Name="listBoxStudent" Height="80">
          <ListBox.ItemTemplate>
              <DataTemplate>
                  <StackPanel Orientation="Horizontal">
                      <TextBlock Text="{Binding Path=Id}" Width="30" Foreground="Red"></TextBlock>
                      <TextBlock Text="{Binding Path=Name}" Width="50"></TextBlock>
                      <TextBlock Text="{Binding Path=Age}" Width="30"></TextBlock>
                  </StackPanel>
              </DataTemplate>
          </ListBox.ItemTemplate>
      </ListBox>

      注意事项:使用集合对象作为列表控件的ItemsSource时,一般会使用ObservableCollection<T>代替List<T>,理由是,ObservableCollection<T>实现了INotifyCollectionChanged和INotifyPropertyChanged接口。

      使用ADO.NET对象作为Binding对象:

      在WPF中支持列表控件与DataTable直接建立Binding。假设已经获得了一个DataTable的实例,数据跟以上的一样。现在Coding把它显示在ListBox中:

    DataTable dt = Load();
     
    this.listBoxStudent.ItemsSource = dt.DefaultView;

    换件“衣服”:

    <ListView x:Name="listViewStudent" Height="120" Margin="5">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Id" Width="60" DisplayMemberBinding="{Binding Id}"></GridViewColumn>
                <GridViewColumn Header="Name" Width="80" DisplayMemberBinding="{Binding Name}"></GridViewColumn>
                <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}"></GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>

    有点注意的:ListView和GridView不是同一级别的控件。ListView是继承自ListBox,GridView是ViewBase的派生类,ListView的View属性是ViewBase的对象。因此,GridView可以作为ListView的View来使用。

    如果想用更复杂的结构来表示标题或者数据,可以为GridViewColumn设置HeaderTemplate和CellTemplate属性,类型都是DataTemplate。

    使用XML数据作为Binding的源: 
    现在程序中涉及到数据传输都离不开XML。XML文本是树形结构,可以方便地用于表示线性集合。

    先Coding一个:

    有这么一个Student.xml,

    <?xml version="1.0" encoding="utf-8" ?>
    <StudentList>
      <Student Id="1">
        <Name>LiLin</Name>
      </Student>
      <Student Id="2">
        <Name>Tom</Name>
      </Student>
      <Student Id="3">
        <Name>Tim</Name>
      </Student>
      <Student Id="4">
        <Name>Luke</Name>
      </Student>
      <Student Id="5">
        <Name>Jake</Name>
      </Student>
      <Student Id="6">
        <Name>LiLi</Name>
      </Student>
    </StudentList>
    XAML:
    <ListView x:Name="listViewStudent" Height="120" Margin="5">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Id" Width="60" DisplayMemberBinding="{Binding XPath=@Id}"></GridViewColumn>
                <GridViewColumn Header="Name" Width="80" DisplayMemberBinding="{Binding XPath=Name}"></GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>
    后台:
    mlDocument xdoc = new XmlDocument();
    xdoc.Load(@"C:Student.xml");
    XmlDataProvider xdp = new XmlDataProvider();
    xdp.Document = xdoc;
    xdp.XPath = @"/StudentList/Student";
     
    this.listViewStudent.DataContext = xdp;
    this.listViewStudent.SetBinding(ListView.ItemsSourceProperty, new Binding());

    注意:XAML中DisplayMemberBinding="{Binding XPath=@Id}"和DisplayMemberBinding="{Binding XPath=Name}"之间的@差异,指明了关注的xml路径不同,使用@表示是XML元素的Attribute,不加的是指子集元素。

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

    因为LINQ查询结果是一个IEnumerable<T>类型的对象,而IEnumerable<T>继承了IEnumerable,所以它可以作为列表控件的ItemsSource来使用。

    Coding:

    List<Student> stu_list = new List<Student>()
    {
        new Student(){Id=0,Name="LiLin",Age=18},
        new Student(){Id=1,Name="LinLi",Age=20},
        new Student(){Id=2,Name="LLiin",Age=24},
        new Student(){Id=3,Name="Tom",Age=27},
        new Student(){Id=4,Name="Tim",Age=19},
        new Student(){Id=5,Name="Luke",Age=23},
    };
     
    this.listViewStudent.ItemsSource = from stu in stu_list where stu.Age <= 20 select stu;
  • 相关阅读:
    no module name cx_oracle 的解决方法
    开通博客
    普通用户启动Hadoop格式化namenode出现无法创建目录的问题
    改写文件权限时出现问题___2
    suse添加普通用户赋予root所有权限时出现问题___1
    suse系统vim未正常退出产生的问题(can't write viminfo file /home/zhaoy/.viminfo)
    intellij idea根据mvn仓库添加或改变scala-sdk
    git拉项目和上传项目时遇到的一些问题
    简单的clone项目fromGitHub
    初始机器学习
  • 原文地址:https://www.cnblogs.com/sjqq/p/6662022.html
Copyright © 2020-2023  润新知