zoukankan      html  css  js  c++  java
  • 网络资源深入剖析Binding2(学习)

    WPF Binding 

    WPF里分三种Binding:BindingPriorityBinding, MultiBinding,这三种Binding的基类都是BindingBase,而BindingBase又继承于MarkupExtension

    Binding:

    提供对绑定定义的高级别访问,绑定将绑定目标对象(通常为 WPF 元素)的属性与任何数据源(例如数据库、XML 文件或包含数据的任何对象)连接起来。

    常见的使用Binding的代码:

    C#

    Binding binding = new Binding();     
    binding.Source = treeView; // Set source object
    binding.Path = new PropertyPath("SelectedItem.Header"); // Set source property
    SetBinding(TextBlock.TextProperty, binding);  // Attach to target property currentFolder.

    所有 FrameworkElement都包含SetBinding方法:SetBinding(DependencyProperty dp, String path), SetBinding(DependencyProperty dp, BindingBase binding),可以看出,FrameworkElement中的SetBinding只对DependencyProperty有效

    另一种设置Binding的方法是:BindingOperations.SetBinding(currentFolder, TextBlock.TextProperty, binding);
    BindingOperations.SetBinding的原型是

    public static BindingExpressionBase SetBinding( DependencyObject target, DependencyProperty dp, BindingBase binding)

    第一个参数是DependencyObject,所以我们可以对自定义DependencyObject或者继承自DependencyObject的类进行绑定。当然第二个参数还是DependencyProperty。

      XAML:

    <TextBlock x:Name=”currentFolder” 
              DockPanel.Dock=”Top”
              Text=”{Binding ElementName=treeView, Path=SelectedItem.Header}”
              Background=”AliceBlue”
              FontSize=”16”/>


    清除Binding:

    BindingOperations.ClearBinding(currentFolder, TextBlock.TextProperty); //删除currentFolder上的TextBlock.TextProperty绑定
    BindingOperations.ClearAllBindings(currentFolder); //删除currentFolder上的所有绑定 

    直接对dependency property赋值也可以解除binding, 不过只对单向binding有效。  


     

    Bingding的源:

    有三个属性用来设置源:ElementName(string)、Source(Object) 和 RelativeSource(RelativeSource)。注:这三个只能指定一个,否则异常
     
    1:ElementName: Xaml最基础的binding,源为一个元素(Element),这里指的设置x:Name属性的那个元素
    2:Source:以object作为源。
    <TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
    3:RelativeSource: 源相对于绑定目标的位置(比如要绑定到之前的几个parent元素)。
    •   源是元素本身的例子:{Binding RelativeSource={RelativeSource Self}}
    •   源是Tempalte中元素的Parent:{Binding RelativeSource={RelativeSource TemplatedParent}}
    •   源是绑定以collection形式的前一个数据:{Binding RelativeSource={RelativeSource PreviousData}},MSDN上关于PreviousData的说明并不多,这里有一篇文章可以参考
      以上三项为RelativeSource中的Static值,使用这些值可以减少内存开销
    •   源是Ancestor(可能比parent还高):{Binding RelativeSource={RelativeSource FindAncestor, AncestorLevel=n, AncestorType={x:Type desiredType}}}
        <Window x:Class="Yingbao.Chapter2.RelativeEx.AppWin"   
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
            Title="相对绑定" Height="100" Width="300">    
            <StackPanel Orientation="Horizontal"    
                        HorizontalAlignment="Center">   
                <TextBlock FontSize="20" Text="{Binding  RelativeSource={RelativeSource self}, Path=FontSize}"/>           
                <TextBlock Margin="10,1,1,5"  FontSize="20" Text="{Binding  RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}, Path=Orientation}"/>                           
            </StackPanel>   
        </Window>  

    在这个例子中,使用了两个相对数据源扩展,第一个TextBlock的Text绑定到自身的字体大小上;第二个TextBlock的Text则绑定到其父节点StackPanel的Orientation属性上。这段XAML的运行结果如图2-5所示。



    Path:

    1:Binding中的Path是PropertyPath对象。在最简单的情况下,Path制定一个源的属性,如 Path=PropertyName

    2:通过类似于 C# 中使用的语法,可以指定子属性。例如,子句 Path=ShoppingCart.Order 将绑定设置为对象的子属性 Order。

       3:若要绑定到附加属性,请将附加属性用括号括起。例如,若要绑定到附加属性 DockPanel.Dock,则语法为 Path=(DockPanel.Dock)。

    4:在应用了索引器的属性名称之后的方括号内,可以指定属性的索引器。例如,子句 Path=ShoppingCart[0] 将绑定设置为与属性的内部索引处理文本字符串“0”的方式对应的索引。此外,还支持多个索引器。在 Path 子句中可以同时使用索引器和子属性,例如,Path=ShoppingCart.ShippingInfo[MailingAddress,Street]。在索引器内部,可以有多个由逗号 (,) 分隔的索引器参数。可以使用圆括号指定每个参数的类型。例如,可以使用 Path="[(sys:Int32)42,(sys:Int32)24]",其中 sys 映射到 System 命名空间。

       5:如果源为集合视图,则可以用斜杠 (/) 指定当前项。例如,子句 Path=/ 设置到视图中当前项的绑定。如果源为集合,则此语法指定默认集合视图的当前项。

    6:可以结合使用属性名和斜杠来遍历作为集合的属性。例如,Path=/Offices/ManagerName 指定源集合的当前项,该源集合包含同样是集合的 Offices 属性。其当前项是包含 ManagerName 属性的对象。

    7:也可以使用句点 (.)路径绑定到当前源。例如,Text=”{Binding}” 等效于 Text=”{Binding Path=.}”。

     


     


    BindingExpression

    Binding 类是高级别类。BindingExpression 类是基础对象,用于保持绑定源与绑定目标之间的连接。Binding 中包含可在多个 BindingExpression 对象之间共享的所有信息。也就是说,可以把一个Binding对象绑定对n个元素上,而针对这n个元素,分别有相应的n个BindingExpresion对象。
    Binding 可以直接绑定普通的.net实例,比如int值。但是如果后台改变int值了,前台不能显示改变后的值,这时可以调用UpdateTarget()方法更 新绑定。如下:

    BindingExpression be = button.GetBindingExpression(Button.ContentProperty);
    be.UpdateTarget();   

    还有UpdateSource方法用来更新源。

     


     

    绑定到.net属性/对象:

     上面提到Binding绑到普通的.net属性,如果source变化了,UI上是不会显示的,除了用BindingExpression每次显式更新Target外,还可以使用如下技术:绑定到单个对象需实现INotifyPropertyChanged接口,这个接口只有一个成员:

    event PropertyChangedEventHandler PropertyChanged
     
    实现INotifyPropertyChanged的示例如下:
    using System.ComponentModel;    
    namespace SDKSample { // This class implements INotifyPropertyChanged // to support one-way and two-way bindings // (such that the UI element updates when the source // has been changed dynamically) public class Person : INotifyPropertyChanged { private string name; // Declare the event public event PropertyChangedEventHandler PropertyChanged; public Person() { } public Person(string value) { this.name = value; } public string PersonName { get { return name; } set { name = value; // Call OnPropertyChanged whenever the property is updated OnPropertyChanged("PersonName"); } } // Create the OnPropertyChanged method to raise the event protected void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } } } 或者显式实现INotifyPropertyChanged:
    #region INotifyPropertyChanged Members  event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged  {      add      {          this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Combine(this.PropertyChanged, value);      }      remove      {          this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Remove(this.PropertyChanged, value);      }  }  #endregion
     
    看了上面代码着实没看出source值改变了,前台是通过什么机制反映的,正常的情况下公开了一个事件,必须有一个对此事件的实现体,而上面代码并没有实现PropertyChanged的方法。
    我猜想是Binding内部获取了这个接口并对PropertyChanged进行了赋值,因为在debug时,这个事件确实被赋值的,而赋值前的Stack是External Code调用的。
     
    绑定到集合需实现INotifyCollectionChanged,但是推荐使用ObservableCollection<T>,这个类实现了INotifyCollectionChanged和INotifyPropertyChanged。
     
    附:当绑定到普通的.net属性时,WPF使用反射取得source的值,当对象实现ICustomTypeDescriptor时,WPF使用这个接口取得值,性能上会有所提升。

     


     


    DataContext:


    DataContext在共享资源时最有用

     
    
    <StackPanel x:Name="parent" DataContext="{StaticResource photos}">  
    <Label x:Name="numItemsLabel"  Content="{Binding Path=Count}"  DockPanel.Dock="Bottom"/>
    
    等价C#中代码是:parent.DataContext = photos;

     

    Value Converters:  IValueConverter可以在绑定时加入自己的逻辑,很好。

    C#中建立converter
    public class RawCountToDescriptionConverter : IValueConverter{

      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)   {     int num = int.Parse(value.ToString()); // Let Parse throw an exception if the input is bad     return num + (num == 1 ? " item" : " items");   }   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)   {     throw new NotSupportedException();   } }
    IValueConverter就两个方法需要自己实现,Convert和ConvertBack,一个转过来,一个转过去。

    XAML代码使用converter
    <Window.Resources> <local:CountToBackgroundConverter x:Key="myConverter"/> </Window.Resources>
    ......
    <Label Background="{Binding Path=Count, Converter={StaticResource myConverter}, Source={StaticResource photos}}"/>

    这里的myConverter是个resource,需要在xaml中预先定义:

    Count值会作为第一个参数value传给Convert方法。
    注意,返回的值一定要是绑定时对应的值,比如绑定时需要绑到Geometry类上,那么Convert返回的也必须是Geometry类。
     
    Convert方法还带有一个parameter参数,可以在xaml中这么使用,这样C#代码中就可以得到parameter的值了。
    <Label Background="{Binding Path=Count, Converter={StaticResource myConverter},   ConverterParameter=Yellow, Source={StaticResource photos}}"/>

    ConverterParameter是object类型。

    TIP:
    可以用Binding.DoNothing作返回值,以指示绑定引擎不要执行任何操作。
    可 用使用[ValueConversion(typeof(DateTime), typeof(String))]来标识Converter要转化和返回的值类型,第一个参数是soure,第二个参数是target。这样在编译时,如 果类型不匹配的话,编译器会抛出异常:error CS0592: Attribute 'ValueConversion' is not valid on this declaration type. It is only valid on 'class' declarations.

    .net自带一些converter,比如常用的BooleanToVisibilityConverter,可以根据checkbox是否勾上来隐藏其他控件。

    常见的使用位置:

    • 在collection中使用converter
    • 使用DateTemplate,在其中使用Converter
    • 也可以使用Converter对整个collection进行转化,但是可能效率不好

     


     Binding.Mode

    指示源和目标间数据流的方向。

    • OneWay 源更新时,目标也更新
    • TwoWay 源更新时目标也更新,或者目标更新时同时更新源
    • OneTime 仅当应用程序启动时或 DataContext 进行更改时更新目标属性。绑一次就不更维护更新,目标相当于源的一次性镜像
    • OneWayToSource 目标更新时更新源,和OneWay相反。OneWayToSource 用于多个目标更改一个源的情况,可以想像成多人录入。或者用来实现源和目标倒置的情况。

    大部分WPF自带的控件的dependency property默认的是OneWay,像TextBox.Text默认的是TwoWay。
    值得注意的事,只读属性只能设置成OneWay,不能是TwoWay,否则运行时异常。

    注意:再次提醒,源要实现INotifyPropertyChanged 接口才能传到目标。

    • 对于 OneWay 或 TwoWay 绑定,对源的动态更改不会自动传播到目标。必须在源对象上实现 INotifyPropertyChanged 接口。
    • 对于 TwoWay 绑定,对目标的更改不会自动传播到源,除非绑定目标是 Text 属性。在这种情况下,更新仅在 TextBox 失去焦点时发生。
    • 对于 OneTime 和 OneWay 绑定,对 SetValue 的调用会自动更改目标值并删除绑定。

     

    Binding实例:   http冒号//www点wpf123点com/news/?8849.html
     
    MainWindow.xaml前台表现:
    View Code
     1 <Window x:Class="Binding2.MainWindow"
     2                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4                 Title="MainWindow" Height="350" Width="525">
     5 
     6     <Window.Resources>
     7         <DataTemplate x:Key="nameDT">
     8             <TextBlock x:Name="textBoxName" Text="{Binding Name}"/>
     9         </DataTemplate>
    10         
    11         <DataTemplate x:Key="skillDT">
    12             <TextBlock x:Name="textBoxSkill" Text="{Binding Skill}"/>
    13         </DataTemplate>
    14         
    15         <DataTemplate x:Key="hmDT">
    16             <CheckBox x:Name="checkBoxJob" IsChecked="{Binding HasM}"/>
    17         </DataTemplate>
    18         
    19     </Window.Resources>
    20         <Grid Margin="5">
    21         <Grid.RowDefinitions>
    22             <RowDefinition Height="3*"/>
    23             <RowDefinition Height="1*"/>
    24         </Grid.RowDefinitions>
    25         <ListView x:Name="listViewHeros" Grid.Row="0">
    26             <ListView.View>
    27                 <GridView>
    28                     <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}"/>
    29                     <GridViewColumn Header="姓名" CellTemplate="{StaticResource nameDT}"/>
    30                     <GridViewColumn Header="能力" CellTemplate="{StaticResource skillDT}"/>
    31                     <GridViewColumn Header="已婚" CellTemplate="{StaticResource hmDT}"/>
    32                     
    33                 </GridView>
    34             </ListView.View>
    35         </ListView>
    36         <Button Grid.Row="1" Content="给关老爷正名!" Click="Button_Click"/>
    37     </Grid>
    38 </Window>
     
    MainWindow.xaml后台数据:
    View Code
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Windows;
      6 using System.Windows.Controls;
      7 using System.Windows.Data;
      8 using System.Windows.Documents;
      9 using System.Windows.Input;
     10 using System.Windows.Media;
     11 using System.Windows.Media.Imaging;
     12 using System.Windows.Navigation;
     13 using System.Windows.Shapes;
     14 using System.ComponentModel;
     15 
     16 namespace Binding2
     17 {
     18     /// <summary>
     19     /// Interaction logic for MainWindow.xaml
     20     /// </summary>
     21     public partial class MainWindow : Window
     22     {
     23 
     24         public class Hero : INotifyPropertyChanged
     25         {
     26             public event PropertyChangedEventHandler PropertyChanged;
     27 
     28             private string skill;
     29             private string name;
     30 
     31             public int Id { get; set; }
     32             public string Name 
     33             {
     34                 get { return name; } 
     35                 set 
     36                 { 
     37                     name = value;
     38                     if (PropertyChanged != null)
     39                     {
     40                         PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
     41                     }
     42                 }
     43             }
     44             public bool HasM { get; set; }
     45             public string Skill 
     46             {
     47                 get { return skill; }
     48                 set 
     49                 {
     50                     skill = value;
     51                     if (PropertyChanged != null)
     52                     {
     53                         PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Skill"));
     54                     }
     55                 }
     56             }
     57 
     58 
     59             public Hero(int id, string name, string skill, bool hasM) 
     60             {
     61                 this.Id = id;
     62                 this.Name = name;
     63                 this.Skill = skill;
     64                 this.HasM = hasM;
     65             }
     66         }
     67 
     68         Dictionary<string, Hero> map = new Dictionary<string, Hero>();
     69 
     70         private void InitDictionary() 
     71         {
     72             Hero hero1 = new Hero(1, "刘备", "哭泣", true);
     73             map.Add(hero1.Name, hero1);
     74             Hero hero2 = new Hero(2, "官羽", "贪污", false);
     75             map.Add(hero2.Name, hero2);
     76             Hero hero3 = new Hero(3, "黄忠", "射击", true);
     77             map.Add(hero3.Name, hero3);
     78             Hero hero4 = new Hero(4, "魏延", "突击", true);
     79             map.Add(hero4.Name, hero4);
     80             Hero hero5 = new Hero(5, "马超", "单挑", false);
     81             map.Add(hero5.Name, hero5);
     82             Hero hero6 = new Hero(6, "曹仁", "防守", true);
     83             map.Add(hero6.Name, hero6);
     84         }
     85         public MainWindow()
     86         {
     87             InitializeComponent();
     88             InitDictionary();
     89             
     90             Binding binding = new Binding();
     91             binding.Source = map;
     92             binding.Path = new PropertyPath("Values");
     93             listViewHeros.SetBinding(ListView.ItemsSourceProperty, binding);
     94 
     95             //listViewHeros.ItemsSource = map.Values;        //可以使用这行来代替上面的binding 90~93
     96         }
     97 
     98         private void Button_Click(object sender, RoutedEventArgs e)
     99         {
    100             map["官羽"].Name = "关羽";
    101             map["官羽"].Skill = "单挑";
    102         }
    103 
    104 
    105     }
    106 }
     
     
  • 相关阅读:
    python-生成器
    python—迭代器
    python—递归函数
    CentOS关闭防火墙
    OpenHCI
    USB电源管理
    USB相关的网络资料
    USB Packet Types
    USB描述符概述
    Core Java Volume I — 1.2. The Java "White Paper" Buzzwords
  • 原文地址:https://www.cnblogs.com/shawnzxx/p/2763544.html
Copyright © 2011-2022 走看看