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使用,則需要這樣的語法。
如果集合元素的屬性還是一個集合,就可以一直斜線下去。
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屬性會沿着樹傳播。
注) DataContext是一個依賴屬性,依賴屬性有個很重要的特點就是當你沒有為控件的某個依賴屬性賦值時,控件會把自己容器的屬性“借過來”當作自己的值。
3. 使用集合對象作為列表控件的ItemsSource
使用ItemsSource屬性來承載IEnumrate集合
使用this.ListBoxStudents.DisplayMemberPath=”Name” 來規定Path。
DispalyMemebrPath這個屬性其實會將這個值傳給ListBoxItem的Path。
注1)創建Binding的過程是在DisplayMemberTemplateSelector類的SelectTemplate方法里面完成的。
可以使用ItemTemplate來創建itemTemplate
注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
3, DataTable不能直接作為Source來使用,但是如果把DataTable對象放在一個對象的DataContext屬性里,並把ItemsSource與一個既沒有指定Source有沒有指定Path的Binding關聯時,Binding能自動找他的DefaultView並當作Source來使用。
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:
如果是屬性則需要在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
注) 這里有個地方注意一下,就是 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抽象類。
使用:
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:
使用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);
如何使用呢?
<local:CategoryToSourceConverter x:Key=”cts” />
Text={Binding Path=Category,Converter={StaticeResource ets}}
9,多路綁定 (MultiBinding)