WPF 笔记 三 绑定
绑定
HelloWorld
<StackPanel Margin="10"> <TextBox Name="txtValue" /> <WrapPanel Margin="0,10"> <TextBlock Text="Value: " FontWeight="Bold" /> <TextBlock Text="{Binding Path=Text, ElementName=txtValue}" /> </WrapPanel> </StackPanel>
Binding 语法
{Binding Path=NameOfProperty}
简略为
{Binding NameOfProperty}
连接其他UI元素的语法
{Binding Path=Text, ElementName=txtValue}
。。
DataContext
<StackPanel Margin="15"> <WrapPanel> <TextBlock Text="Window title: " /> <TextBox Text="{Binding Title}" Width="150" /> </WrapPanel> <WrapPanel Margin="0,10,0,0"> <TextBlock Text="Window dimensions: " /> <TextBox Text="{Binding Width}" Width="50" /> <TextBlock Text=" x " /> <TextBox Text="{Binding Height}" Width="50" /> </WrapPanel> </StackPanel>
在cs文件中
InitializeComponent(); this.DataContext = this;
xaml绑定的property都是Window对象自身比如title,宽,高。
Window本身的这些属性改变时,值会立即反映到UI显示上。
如果UI上的值改变,需要焦点移动到其他UI控件,Window的那些宽高才会改变。此时UpdateSourceTrigger的值为LostFocus
如果需要Window的那些宽高立即生效的话,binding后面加上UpdateSourceTrigger=PropertyChanged
<TextBox Text="{Binding Width,UpdateSourceTrigger=PropertyChanged}" Width="50" />
UpdateSourceTrigger的值一共有
1.Explicit
2.LostFocus
3.PropertyChanged
对于Explicit,这基本上意味着除非您手动执行,否则不会更新源。
explicit手动更新的例子:
<TextBox Name="txtWindowTitle" Text="{Binding Title, UpdateSourceTrigger=Explicit}" Width="150" />
后台代码
BindingExpression binding = txtWindowTitle.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
后台代码实现HelloWorld例子中的绑定
<StackPanel Margin="10"> <TextBox Name="txtValue" /> <WrapPanel Margin="0,10"> <TextBlock Text="Value: " FontWeight="Bold" /> <TextBlock Name="lblValue" /> </WrapPanel> </StackPanel>
InitializeComponent(); Binding binding = new Binding("Text"); binding.Source = txtValue; lblValue.SetBinding(TextBlock.TextProperty, binding);
响应数据变化
<DockPanel Margin="10"> <StackPanel DockPanel.Dock="Right" Margin="10,0,0,0"> <Button Name="btnAddUser" Click="btnAddUser_Click">Add user</Button> <Button Name="btnChangeUser" Click="btnChangeUser_Click" Margin="0,5">Change user</Button> <Button Name="btnDeleteUser" Click="btnDeleteUser_Click">Delete user</Button> </StackPanel> <ListBox Name="lbUsers" DisplayMemberPath="Name"></ListBox> </DockPanel>
后台
public partial class MainWindow : Window { private ObservableCollection<User> users = new ObservableCollection<User>(); public MainWindow() { InitializeComponent(); users.Add(new User() { Name = "John Doe" }); users.Add(new User() { Name = "Jane Doe" }); lbUsers.ItemsSource = users; } private void btnAddUser_Click(object sender, RoutedEventArgs e) { users.Add(new User() { Name = "New user" }); } private void btnChangeUser_Click(object sender, RoutedEventArgs e) { if (lbUsers.SelectedItem != null) (lbUsers.SelectedItem as User).Name = "Random Name"; } private void btnDeleteUser_Click(object sender, RoutedEventArgs e) { if (lbUsers.SelectedItem != null) users.Remove(lbUsers.SelectedItem as User); } } public class User : INotifyPropertyChanged { private string name; public string Name { get { return this.name; } set { if (this.name != value) { this.name = value; this.NotifyPropertyChanged("Name"); } } } public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged(string propName) { if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(propName)); } }
RelativeSource例子说明
<StackPanel Margin="10,50,0,0" Orientation="Vertical" ToolTip="top" > <StackPanel Orientation="Horizontal" > <TextBlock Width="150" Text="获取自身宽度:" ></TextBlock> <TextBlock Width="200" Text="{Binding Path=Width,RelativeSource={RelativeSource Mode=Self}}" ></TextBlock> </StackPanel> <StackPanel Orientation="Horizontal" ToolTip="parent" > <TextBlock Width="150" Text="查找上一层ToolTip:" ></TextBlock> <TextBlock Text="{Binding Path=ToolTip,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type StackPanel}}}"></TextBlock> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Width="150" Text="查找上二层ToolTip:" ></TextBlock> <TextBlock Text="{Binding Path=ToolTip,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type StackPanel},AncestorLevel=2}}"></TextBlock> </StackPanel> </StackPanel>
运行显示
创建RelativeSource的时候,mode模式有四种类型:
Mode成员名称 | 说明 | |
---|---|---|
FindAncestor |
引用数据绑定元素的父链中的上级。 这可用于绑定到特定类型的上级或其子类。 若要指定 AncestorType 和/或 AncestorLevel,这就是应使用的模式。 |
|
PreviousData |
允许在当前显示的数据项列表中绑定上一个数据项(不是包含数据项的控件)。 |
|
Self |
引用正在其上设置绑定的元素,并允许你将该元素的一个属性绑定到同一元素的其他属性上。 |
|
TemplatedParent |
引用应用了模板的元素,其中此模板中存在数据绑定元素。 这类似于设置 TemplateBindingExtension,且仅在 Binding 位于模板内部时适用。 |
Binding Source RelativeSource
Source
Source属性通常用于绑定设置的对象时,是已知的
<Window x:Name="MainWindow"> <Grid> <Button Background=”{Binding Source={StaticResource ButtonStyle}}”/> </Grid> </Window>
RelativeSource
由于不能确定Source的对象叫什么名字,但知道它与作为Binding目标的对象在UI布局上有相对关系,比如控件自己关联自己的某个数据、关联自己某级容器的数据,就要使用Binding的RelativeSource属性。
RelativeSource 的三种典型用法:
/1.UI元素的一个属性绑定在自身的另一个属性上
<Label Background = {Binding Path=Forgroud, RelativeSource={RelativeSource Self}} />
/2.UI元素的一个属性绑定在某个父元素的属性上
<Grid> <Label Background = {Binding Path=Background, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}/> </Grid>
/3.Template中的元素的属性绑定在Template使用者元素的属性上
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
如果要绑定到对象上的另一个属性:
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
如果您想获得祖先的属性:
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
如果希望获得模板父级上的属性(因此可以在ControlTemplate中执行双向绑定)
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
或者,更短的(这只适用于OneWay绑定):
{TemplateBinding Path=PathToProperty}
例子1:
<StackPanel DataContext="abc"> <Label Content="{Binding}"></Label> <Label Content="{Binding RelativeSource={RelativeSource Self},Path=DataContext}"></Label> </StackPanel>
例子2:
<StackPanel DataContext="abc"> <Label Content="{Binding}"></Label> <Label DataContext="def" Content="{Binding RelativeSource={RelativeSource Self},Path=DataContext}"></Label> </StackPanel>
Binding 为空等效于
{Binding RelativeSource={RelativeSource Self},Path=DataContext}
从本控件类为开始根据可视树的层次结构自下而上查找不为空的Datacontext属性的值。