WPF BINDING

WPF裏分三種Binding:Binding, PriorityBindingMultiBinding,這三種Binding的基類都是BindingBase,而BindingBase又繼承於MarkupExtensionhtml

Binding

提供對綁定定義的高級別訪問,綁定將綁定目標對象(一般爲 WPF 元素)的屬性與任何數據源(例如數據庫、XML 文件或包含數據的任何對象)鏈接起來。數據庫

常見的使用Binding的代碼:
C#windows

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

XAML:性能

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

全部FrameworkElement都包含SetBinding方法:SetBinding(DependencyProperty dp, String path), SetBinding(DependencyProperty dp, BindingBase binding),能夠看出,FrameworkElement中的SetBinding只對DependencyProperty有效。this

另外一種設置Binding的方法是:BindingOperations.SetBinding(currentFolder, TextBlock.TextProperty, binding);
BindingOperations.SetBinding的原型是spa

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

第一個參數是DependencyObject,因此咱們能夠對自定義DependencyObject或者繼承自DependencyObject的類進行綁定。固然第二個參數仍是DependencyProperty。.net

清除Binding:
BindingOperations.ClearBinding(currentFolder, TextBlock.TextProperty); //刪除currentFolder上的TextBlock.TextProperty綁定
BindingOperations.ClearAllBindings(currentFolder); //刪除currentFolder上的全部綁定debug

直接對dependency property賦值也能夠解除binding, 不過只對單向binding有效。  component


Bingding的源:

有三個屬性用來設置源:ElementName(string)、Source(Object) 和 RelativeSource(RelativeSource)。注:這三個只能指定一個,不然異常。
ElementName: 源爲一個元素(Element),這裏用的是此元素中設置的Name屬性。
Source:以object做爲源。<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
RelativeSource: 源相對於綁定目標的位置。
                        源是元素自己:{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}}}htm


Path:

Binding中的Path是 PropertyPath對象。

    • 在最簡單的狀況下,Path 屬性值是要用於綁定的源對象的屬性名稱,如 Path=PropertyName。

    • 經過相似於 C# 中使用的語法,能夠指定屬性的子屬性。例如,子句 Path=ShoppingCart.Order 將綁定設置爲對象的子屬性 Order 或屬性 ShoppingCart。

    • 若要綁定到附加屬性,請將附加屬性用括號括起。例如,若要綁定到附加屬性 DockPanel.Dock,則語法爲 Path=(DockPanel.Dock)。

    • 在應用了索引器的屬性名稱以後的方括號內,能夠指定屬性的索引器。例如,子句 Path=ShoppingCart[0] 將綁定設置爲與屬性的內部索引處理文本字符串「0」的方式對應的索引。此外,還支持多個索引器。

    • 在 Path 子句中能夠同時使用索引器和子屬性,例如,Path=ShoppingCart.ShippingInfo[MailingAddress,Street]。

    • 在索引器內部,能夠有多個由逗號 (,) 分隔的索引器參數。可使用圓括號指定每一個參數的類型。例如,可使用 Path="[(sys:Int32)42,(sys:Int32)24]",其中 sys 映射到 System 命名空間。

    • 若是源爲集合視圖,則能夠用斜槓 (/) 指定當前項。例如,子句 Path=/ 設置到視圖中當前項的綁定。若是源爲集合,則此語法指定默認集合視圖的當前項。

    • 能夠結合使用屬性名和斜槓來遍歷做爲集合的屬性。例如,Path=/Offices/ManagerName 指定源集合的當前項,該源集合包含一樣是集合的 Offices 屬性。其當前項是包含 ManagerName 屬性的對象。

      也可使用句點 (.)路徑綁定到當前源。例如,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"/>
      也能夠在代碼這麼寫parent.DataContext = photos;
       

       


       

      Value Converters:

      IValueConverter能夠在綁定時加入本身的邏輯,很好。

      public class RawCountToDescriptionConverter : IValueConverter
      {
      	public object Convert(object value, Type targetType, object parameter,
      		CultureInfo culture)
      	{
      		// Let Parse throw an exception if the input is bad
      		int num = int.Parse(value.ToString());
      		return num + (num == 1 ? " item" : " items");
      	}
      
      	public object ConvertBack(object value, Type targetType, object parameter,
      		CultureInfo culture)
      	{
      		throw new NotSupportedException();
      	}
      }
      IValueConverter就兩個方法須要本身實現,Convert和ConvertBack,一個轉過來,一個轉過去。
      XAML代碼以下
      <Label Background="{Binding Path=Count, Converter={StaticResource myConverter},
      Source={StaticResource photos}}"/>
      這裏的myConverter是個resource,須要在xaml中預先定義:
      <Window.Resources>
      <local:CountToBackgroundConverter x:Key="myConverter"/>
      </Window.Resources>
       
      Path對應的Count值會做爲第一個參數value傳給Convert方法。
       
      注意,返回的值必定要是綁定時對應的值,好比綁定時須要綁到Geometry類上,那麼Convert返回的也必須是Geometry類。
       
      Convert方法還帶有一個parameter參數,能夠在xaml中這麼使用
      <Label Background="{Binding Path=Count, Converter={StaticResource myConverter}, 
      ConverterParameter=Yellow, Source={StaticResource photos}}"/>

      ConverterParameter是object類型。
      C#代碼中就能夠獲得parameter的值了。

      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相反

      大部分WPF自帶的控件的dependency property默認的是OneWay,像TextBox.Text默認的是TwoWay。
      值得注意的事,只讀屬性只能設置成OneWay,不能是TwoWay,不然運行時異常。

      對於 OneWay 或 TwoWay 綁定,對源的動態更改不會自動傳播到目標。必須在源對象上實現 INotifyPropertyChanged 接口。 
      對於 TwoWay 綁定,對目標的更改不會自動傳播到源,除非綁定目標是 Text 屬性。在這種狀況下,更新僅在 TextBox 失去焦點時發生。 
      對於 OneTime 和 OneWay 綁定,對 SetValue 的調用會自動更改目標值並刪除綁定。

      再次提醒,源要實現了INotifyPropertyChanged 接口才能把改變反映到目標上。

      OneWayToSource 用於多個目標更改一個源的狀況,能夠想像成多人錄入。或者用來實現源和目標倒置的狀況。

       


       

      Binding.UpdateSourceTrigger

      指示使用TwoWay或OneWayToSource時,目標在什麼狀況下更新源。有三個枚舉值

      PropertyChanged:目標屬性改變時更新源
      LostFocus:失去焦點時更新源
      Explicit:只有在顯式調用BindingExpression.UpdateSource方法時才更新源。BindingExpression能夠經過BindingOperations.GetBindingExpression或FrameworkElement.GetBindingExpression方法得到

      Binding類中提供了SourceUpdated和TargetUpdated事件,能夠用來記些log,不過必須相應的NotifyOnSourceUpdated或NotifyOnTargetUpdated設置成true纔會激發事件。

       

       


       

      Binding的驗證

       

      咱們固然能夠本身寫代碼驗證數據的正確性,不過WPF提供了能夠說是標準的方案,限於篇幅,我單獨開了一貼,點這裏查看。

    • http://www.cnblogs.com/iwteih/archive/2010/02/03/1662891.html
相關文章
相關標籤/搜索