Johnny with dotnet

WPF 学习笔记3 -Binding

1。 Binding的理解: banding像是架在一个Source和一个target之间的桥梁,在binding的途中可以进行数据转换或者验证。

1)一个source可能有多个属性,绑定到哪个属性是由Path决定的。如果想要通知属性已经变化的话,就需要在Set语句中介入一个PropertyChanged事件。

     很容易实现,只要让这个类继承INotifyPropertyChanged接口即可。

     public class ConverterElement : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private double mm;

        public double MM
        {
            get { return mm; }
            set
            {
                mm = value;
                if (this.PropertyChanged != null)
                {
                    PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Mil"));
                 }
              }
            }

          }

2) banding的实现

       Stu = new Student();

       Binding binding = new Binding();

       binding.Source = stu;

       binding.Path = new PropertyPath(“Name”);

       //使用binding连接数据源和Binding目标

       BindingOperations.SetBinding(this.textboxName,TextBox.TextProperty,binding);

       注1:)BindingOperations.SetBinding方法,有三个参数,分别是Targe,Target的依赖属性(dependencyProperty),和Binding

       注2:)因为FrameworkElement对BindingOperations.SetBinding方法进行了封装,所以可以用以下方式绑定:

               this.textBoxName.SetBindng(TextBox.TextProperty,new Binding(“Name”){Source=stu=new Student()});

3) Binding的源与路径

  •     把控件作为Binding源于Binding标记扩展

               使用以下代码binding:

               Text=”{Binding Path=Value,ElementName=slider1}”

             或者: this.textBox1.SetBinding(TextBox.TextPropety,new Binding(“Value”){ElementName=”slider1”})

  • 控制binding的方向和数据更新

               使用Mode来控制数据的流向: TwoWay,OneWay,OnTime,OneWayToSource和Default。

              默认情况下,要在控件失去focus以后才会更新数据,如何实时的实现呢?

              使用UpdateSourceTrigger属性, 可以取得值为PropertyChanged(这个可以实时更新),LostFocus,Explicit和default。

              注1)Binding还有NotifyOnSourceUpdated和NotiryOntargetUpdate两个bool类型的属性,如果设为true,则当源或目标被更新后Binding会激发相应的SourceUpdated事件和targetUpdated事件。

  • Binding的路径(Path)

              Path的真实类型是PropertyPath。

             Path支持多级路径: 比如 {Binding Path=Text.Length}

             集合类型可以使用索引器: 比如{Binding Path=Text.[3]} 或者{Binding Path=Text[3]}

             当使用一个集合或者DataView作为Binding源时,我们如果想把它的默认元素当作Path使用,则需要这样的语法。

              image

              如果集合元素的属性还是一个集合,就可以一直斜线下去。

                        image

4)没有Path的binding

      有些时候,你会看到Path是一个“.”或者干脆没有。这是因为源本身就是数据,想String和Int,这时候我们只需要将path的值设置成“.”就行了。

       Text={Binding Path=.,Source={Staticresource ResourceKey=myString}}

       Text={Binding Source={Staticresource ResourceKey=myString}}

5) 为Binding指定源(Source)的几种方法

  •       普通的单个对象来指定为Source: 如果实现了INotifyPropertyChanged接口,则可通过在属性的Set语句中激发PropertyChanged事件即可通知Binding数据已经更新。
  • 把普通的CLR集合类型对象指定为Source,包括数组,List<T>,ObservableCollention<T>
  • ADO.Net数据对象指定为source。包括DataTable和DataView
  • 使用XmlDataProvider把Xml数据指定为Source。
  • 把依赖对象(dependency Object)指定为Source: 这个既可以做源又可以做目标
  • 把容器的DataContext指定为Source(WPF Data Binding的默认行为):
  • 通过ElementName指定Source
  • 通过Binding的RelativeSource属性相对的指定Source:当控件需要关注自己的,自己容器的或者自己内部元素的某个值就要用这种方法。
  • 把ObjectDataProvider对象指定为Source:当数据源的数据不是通过属性而是通过方法暴露给外界的时候,就可以使用这个对象来包装数据源再把他们定位Source。
  • 使用Linq检索到的数据对象作为Binding的源

2.   没有Source的Binding - 使用DataContext作为Binding的源

     DataContext属性在FrameworkElement类中,所以所有的WPF控件都有DataContext属性。

      DataContext属性会沿着树传播。

      image

      注) DataContext是一个依赖属性,依赖属性有个很重要的特点就是当你没有为控件的某个依赖属性赋值时,控件会把自己容器的属性“借过来”当作自己的值。

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

使用ItemsSource属性来承载IEnumrate集合

使用this.ListBoxStudents.DisplayMemberPath=”Name” 来规定Path。

DispalyMemebrPath这个属性其实会将这个值传给ListBoxItem的Path。

注1)创建Binding的过程是在DisplayMemberTemplateSelector类的SelectTemplate方法里面完成的。

可以使用ItemTemplate来创建itemTemplate

image

注2) 一般使用ObservableCollection<T>来代替List<T>,以为前者实现了INotifyCollectionChanged和INotifyPropertyChanged接口,能把集合的变化立即通知他的列表控件。

4.使用ADO.NET对象作为Binding的源。

1,DataTable     this.listBoxStudents.ItemsSource = dt.DefaultView;

2, Binding到GridView,gridview的内容是columns(GridViewColumnCollection). 它有一个属性是DisplayMemberBinding

   image

3, DataTable不能直接作为Source来使用,但是如果把DataTable对象放在一个对象的DataContext属性里,并把ItemsSource与一个既没有指定Source有没有指定Path的Binding关联时,Binding能自动找他的DefaultView并当作Source来使用。

    image

5. 以XML数据为Binding的源

.net framwork有两套XML数据的类库

  • 符合DOM标准的类库: 包括XmlDocument XmlElement XmlNode XmlAttribute等类
  • 以Linq为基础的类库。包括XDocument XElement XNode XAttribute等类。

注) 使用Xml数据作为Binding的Source时,我们使用XPath属性而不是Path属性来指定数据的来源。

Demo:

    xml:

<XmlDataProvider XPath="Student\Name" x:Key="xmlProvider">
            <x:XData>
                <StudentList xmlns="">
                    <Student Id="1">Tom</Student>
                    <Student Id="2">Jam</Student>
                    <Student Id="3">Dean</Student>
                </StudentList>
            </x:XData>
        </XmlDataProvider>

Xaml:

      image

如果是属性则需要在XPath前面加@, 而对象则不需要。

后代代码:

  XmlDocument doc = new XmlDocument();

  doc.Load(@”D:\RawData.xml”);

  XmlDataProvider xdp = new XmlDataProvider();

  // xdp.Document = doc;

   //这里还可以使用Source属性:

    xdp.Source = new Uri(@”D:\RawData.xml”)

   xdp.XPath = @”/StudentList/Student”;

           this.listViewStudent.DataContext = xdp;

           this.listViewStudent.SetBinding(ListView.ItemsSourceProperty,new Binding())

2) 使用TreeView来表示多层xmlsource

image

image

注) 这里有个地方注意一下,就是 HierarchicalDataTemplate有一个itemsSource属性。

如果是多级的话,可以使用hierarchicalDataTemplate.ItemTemplate属性。

6, 使用Linq检索结果作为binding的源

因为Linq的结果继承自IEnumerable<T>,所以可以直接绑定ItemsSource来使用。

在XML中这样使用:

    this.ListViewStudent.ItemsSource=

     from element in xdoc.Descendants(“Student”)

    where element.Attribute(“Name”).Value.StartWith(“T”)

    selete new Student()

{

    Id  = element.Attribute(“Id”).Value;

}

7,使用ObjectDataProvider对象作为Binding的Source

XmlDataProvider和ObjectDataProvider的父类都是DataSourceProvider抽象类。

image

使用:

ObjectDataProvider odp= new  ObjectDataProvider();

obp.ObjectInstance = new Calculator();

obp.MethodName=”Add”;

obp.MethodParameters.Add(“100”);

obp.MethidParameters.Add(“200”);

MessageBox.Show(odp.Data.ToString())';

使用2:

{

ObjectDataProvider odp= new  ObjectDataProvider();

obp.ObjectInstance = new Calculator();

obp.MethodName=”Add”;

obp.MethodParameters.Add(“0”);

obp.MethidParameters.Add(“0”);

 

//为TextBox1创建一个binding

Binding BindingToArg1 = new Binding(“MethodParameter[0]”)

{

    Source  = odp,BindDirectlyToSource=true,UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged

};

//为TextBox2创建一个binding

Binding BindingToArg2 = new Binding(“MethodParameter[1]”)

{

    Source  = odp,BindDirectlyToSource=true,UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged

};

//为Result创建绑定

Binding bindingToresult= new Binding(“.”){Source=odp};

 

this.Textbox1.SetBinding(TextBox.textProperty,bindingToArg1);

this.Textbox2.SetBinding(TextBox.textProperty,bindingToArg2);

this.TextboxResult.SetBinding(TextBox.textProperty,bindingToResult;)

}

(Note1): BindsDirectlyToSource=true这句话的意思是告诉Binding对象只负责把从UI元素收集到的数据写入它的直接Source,也就是ObjectDataProvider,而不是其包装的Calculator对象。

8,使用Binding的RelativeSource

1,如果binding的source不明确,比如关联自己的某个数据,uhozhe关联自己某级容器的数据。这时候可以考虑使用Binding的RelativeSource属性。

2,Demo:

image

使用RelativeSource来bindingText

RelativeSource rs = new relativeSource(RelativeSourceMode.FindAncestor);

rs.AncestorLevel=1;

rs.AncestorType=typeof(Grid);

Binding binding = new Binding(“Name”){RelativeSource = rs};

this.TextBox1.SetBinding(Textbox.TextProperty,binding);

或者使用xaml

Text = {Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Grid},AncestorLevel=1},Path=Name};

3,如果TextBox需要关联自身的Name属性,则代码应该是这样的:

Public Window1()

{

   RelativeSource  rs= new RelativeSource();

   rs.Mode = RelativeSourceMode.Self;

    Binding binding = new Binding(“Name”) {RelativeSource=rs};

  this.TextBox1.SetBinding(TextBox.TextProperty,binding);

}

9,Binding对数据的转换与校验

1,校验: ValidationRule ,自定义ValidationRule需要继承ValidationRule类

然后实现ValidationResult Validate(Object value,System.Globalization.CultureInfo cultrueInfo)方法。

    使用:

     Binding binding = new Binding(“value”) {Source = this.slider1};

      binding.UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged;

      SelfDefineValidationRule rvr = new SelfDefineValidationRule();

      rvr.ValidatesOnTargetUpdated = true;

      binding.ValidationRules.Add(rvr);//这里可以加入多个校验类实例。

     (note1):如果来自Source的数据也有可能出问题,则需要将校验条件的ValidatesOnTargetUpdated属性设置为true。

       如果想要将校验的结果,可以Binding.NotifyOnValidationError = true;

       this.textBox1.AddHandler(Validation.ErrorEvent,new RoutedEventHandler(this.ValidationError));

       this.textBox1.ToolTip = Validation.GetErrors(this.textBox1)[0].ErrorContent.Tostring();

2,数据转换  继承自IvalueConverter

    public interface IValueConverter

    object Convert(object value,Type targetType,object Parameter,CultureInfo culture);

image

如何使用呢?

<local:CategoryToSourceConverter x:Key=”cts” />

Text={Binding Path=Category,Converter={StaticeResource ets}}         

9,多路绑定 (MultiBinding)

image

image

posted on 2012-11-26 10:36  JohnnyNet  阅读(5684)  评论(3编辑  收藏  举报

导航