网络资源-深入剖析Binding2(学习)
WPF Binding?
WPF里分三種Binding:Binding, PriorityBinding, 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的原型是
第一個參數是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的說明并不多,這里有一篇文章可以參考
- 源是Ancestor(可能比parent還高):{Binding RelativeSource={RelativeSource FindAncestor, AncestorLevel=n, AncestorType={x:Type desiredType}}}
在這個例子中,使用了兩個相對數據源擴展,第一個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]。在索引器內部,可以有多個由逗號 (,) 分隔的索引器參數??梢允褂脠A括號指定每個參數的類型。例如,可以使用 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()方法更 新綁定。如下:
還有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在共享資源時最有用。
?
?
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 用于多個目標更改一個源的情況,可以想像成多人錄入?;蛘哂脕韺崿F源和目標倒置的情況。
大部分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 }?
轉載于:https://www.cnblogs.com/shawnzxx/archive/2012/11/10/2763544.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的网络资源-深入剖析Binding2(学习)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyCharm学习笔记04:PyChar
- 下一篇: loadrunner 配置远程监控win