《深入浅出WPF》6.0 绑定
数据是编程的核心
6.1 DataBinding重要性
程序三层结构:数据存储、数据处理、数据表示
算法分布:数据库内部、读写数据、业务逻辑、数据展示、界面与逻辑的交互
逻辑层优于展示层的功能支持:DataBinding、DependencyProperty、
DataTemplate
6.2 Binding的实现
定义类:注意要实现接口INotifyPerportyChanged自动通知属性发生变化更新数据,this.PropertyChanged.Invoke调用
public class Studet : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
public string Name
{
get { return name; }
set
{
name = value;
if (PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
UI编写:
<StackPanel>
<TextBox x:Name="textbox1"/>
<Button x:Name="Button1" Content="修改" Width="130" Click="Button1_Click"/>
</StackPanel>
绑定方式1:
//实例化绑定类
Binding binding = new Binding();
binding.Source = studet;
binding.Path = new PropertyPath("Name");
//绑定
BindingOperations.SetBinding(this.textbox1, TextBox.TextProperty, binding);
绑定方式2:
this.textbox1.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = studet = new Studet()});
6.3 绑定源与路径
- Class对象
- 自己或自己的容器、子集元素作为源
- 另一个控件
- 集合作为ItemsControl源
- XML作为TreeView或Menu源
- 多个控件关联到一个数据源
绑定自己
6.3.1控件作为数据源
XAML中绑定
<TextBox x:Name="textbox2" Text="{Binding ElementName=Slider1,Path=Value}" BorderBrush="Black"/>
<Slider x:Name="Slider1"/>
C# 中绑定
this.textbox3.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "Slider2" });
6.3.2 绑定的方向及数据更新
绑定方向:Mode
数据更新触发方式:UpdateSourceTrigger
<TextBox x:Name="textbox1" Text="{Binding ElementName=Slider1,Path=Value,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}" />
# 注意
* NotifySourceUpdated设置为TREU会触发SourceUpdated事件
* NofifyTargetUpdated设置为TRUE会触发TargetUpdated事件
6.3.3 绑定的路径Path
绑定支持多级路径
<TextBox x:Name="textbox2" BorderBrush="Black"/>
<TextBox Text="{Binding ElementName=textbox2,Path=Text.Length,Mode=OneWay}"/>
<TextBox Text="{Binding ElementName=textbox2,Path=Text.[3],Mode=OneWay}"/>
<TextBox Text="{Binding ElementName=textbox2,Path=Text[3],Mode=OneWay}"/>
当使用集合元素作为绑定值时,把默认元素当作Path使用,使用斜杠/,可以使用多级斜杠
List<string> StringList = new List<string>() { "Tim", "Tom", "Blog" };
textbox3.SetBinding(TextBox.TextProperty, new Binding("/") { Source = StringList });
textbox4.SetBinding(TextBox.TextProperty, new Binding("/[2]") { Source = StringList,Mode=BindingMode.OneWay });
textbox5.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = StringList,Mode=BindingMode.OneWay });
6.3.4 没有绑定路径的Path
应用于直接取绑定对象本身的值,Path在XAML中可以不写或者写点号,但是在C#中需要写
<StackPanel>
<StackPanel.Resources>
<sys:String x:Key="string1">AAAAA</sys:String>
</StackPanel.Resources>
<TextBox x:Name="textbox1" Text="{Binding Path=., Source={StaticResource ResourceKey=string1},Mode=OneWay}"/>
</StackPanel>
string string1 = "ABCDEF";
textbox2.SetBinding(TextBox.TextProperty, new Binding(".") { Source = string1 });
6.3.5 为绑定指定源
绑定源:
- CLR类型单个对象,如果要实现数据更新通知,要实现INotifyPropertyChanged接口,激发PropertyChanged事件,如Class
- CLR类型集合,如数组、List
等 - ADO.NET数据对象,如Datatable和DataView等
- XMLDtatprovider提供的XML数据,可应用于TreeView等控件
- 依赖对象(dependencyProperty)
- 容器的DataContext
- XAML通过Element指定
- 通过Binding的RelativeSource指定
- ObjectDataProvider
- LINQ检索
6.3.6 DataContext作为绑定源
每一个WPF控件都拥有DataContext属性,UI元素树每一个节点都拥有该属性
默认没有写绑定Source,那么会默认向根部寻找所有节点的DataContext属性的Path
<StackPanel>
<StackPanel.DataContext>
<local:student Age="5" Name="tom" ID="34"/>
</StackPanel.DataContext>
<Grid>
<StackPanel>
<TextBox Text="{Binding Path=Age}"/>
<TextBox Text="{Binding Path=Name}"/>
<TextBox Text="{Binding Path=ID}"/>
</StackPanel>
</Grid>
</StackPanel>
# 注意,这个只能向根结点找数据,因为属性值沿着UI元素向下传递,如果内层未设置属性,则属性值会向下传递
<StackPanel DataContext="ABD">
<StackPanel>
<Grid>
<Grid>
<Grid >
<Button Height="50" x:Name="BTN1" Click="BTN1_Click"/>
</Grid>
</Grid>
</Grid>
</StackPanel>
</StackPanel>
private void BTN1_Click(object sender, RoutedEventArgs e)
{
BTN1.Content = BTN1.DataContext;
}
失败案例:
<StackPanel>
<Grid>
<StackPanel>
<TextBox Text="{Binding Path=Age}"/>
<TextBox Text="{Binding Path=Name}"/>
<TextBox Text="{Binding Path=ID}"/>
<StackPanel>
<StackPanel.DataContext>
<local:student Age="5" Name="tom" ID="34"/>
</StackPanel.DataContext>
</StackPanel>
</StackPanel>
</Grid>
</StackPanel>
6.3.7 Itemsource集合对象作为源
ItemsSource属性:设置对象源
DisplayMemberPath属性:设置显示的属性
示例一:
<StackPanel x:Name="stackPanel" Background="LightBlue">
<TextBlock Text="studentID:" FontWeight="Bold" Margin="5"/>
<TextBox x:Name="textBoxId" Margin="5"/>
<TextBlock Text="Stdent List:" FontWeight="Black" Margin="5"/>
<ListBox x:Name="ListBoxStudents" Height="110" Margin="5"/>
</StackPanel>
public Window6()
{
InitializeComponent();
List<student> students = new List<student>()
{
new student(){Id=0,Name="Tom",Age=29},
new student(){Id=1,Name="Tim",Age=28},
new student(){Id=2,Name="Kyle",Age=27},
new student(){Id=3,Name="Tony",Age=26},
new student(){Id=4,Name="Vina",Age=25},
new student(){Id=5,Name="Mike",Age=24},
};
this.ListBoxStudents.ItemsSource = students;
this.ListBoxStudents.DisplayMemberPath = "Name";
Binding binding = new Binding("SelectedItem.Id") { Source = this.ListBoxStudents };
this.textBoxId.SetBinding(TextBox.TextProperty, binding);
}
public class student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
# 注意其中
* ItemsSource、DisplayMemberPath使用
* SelectedItem.Id的使用
示例二删除DisplayMemberPath属性后,通过模板方式在XAML中使用:
<StackPanel x:Name="stackPanel" Background="LightBlue">
<TextBlock Text="studentID:" FontWeight="Bold" Margin="5"/>
<TextBox x:Name="textBoxId" Margin="5"/>
<TextBlock Text="Stdent List:" FontWeight="Black" Margin="5"/>
<ListBox x:Name="ListBoxStudents" Height="110" Margin="5">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Id}" Width="30"/>
<TextBlock Text="{Binding Path=Name}" Width="60"/>
<TextBlock Text="{Binding Path=Age}" Width="30"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
# 注意
* 一般建议用ObservableCollection替代List,因为继承了INotifyCollectionChanged和INotifyproperChanged
6.3.8使用ADO.net作为源
使用属性:ItemSource、DisplaymemberPath
DataTable dataTable= this.Loadtb();
this.Listbox1.DisplayMemberPath = "Name";
this.Listbox1.ItemsSource = dataTable.DefaultView;
使用ListView
//this.Lisview1.ItemsSource = this.Loadtb().DefaultView;
this.Lisview1.DataContext = this.Loadtb();
this.Lisview1.SetBinding(ListView.ItemsSourceProperty, new Binding());
<StackPanel>
<ListView x:Name="Lisview1" Height="200" BorderBrush="Black">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Path=Id}" Width="60"/>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" Width="60"/>
<GridViewColumn Header="Age" DisplayMemberBinding="{Binding Path=Age}" Width="60"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
6.3.9 使用XML作为绑定源
<Window.Resources>
<XmlDataProvider x:Key="xdp" XPath="Filesystem/Folder">
<x:XData>
<Filesystem xmlns="">
<Folder Name="Books">
<Folder Name="Programming">
<Folder Name="Windows">
<Folder Name="WPF"/>
<Folder Name="MFC"/>
<Folder Name="Delphi"/>
</Folder>
</Folder>
<Folder Name="Tools">
<Folder Name="Development"/>
<Folder Name="Designment"/>
<Folder Name="Players"/>
</Folder>
</Folder>
</Filesystem>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding Source={StaticResource xdp}}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding XPath=Folder}">
<CheckBox Content="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>