WPF 神话之Binding对象二
今天我们来探讨的问题,有两个:一是:关于Binding的几个属性问题(Path,Source) 二是:关于几种数据源问题。
首先来看第一个问题:
第一个属性:Source:这个数据源有很多种,在接下来我会大家提供几个数据源的例子信息。
第二个属性:Path,这里将要重点介绍这个属性
在XAML文件中写Binding的时候。这里的Path是可以不用写的。比如说:
<GridViewColumn Header="Age" Width="220" DisplayMemberBinding="{Binding Age}"></GridViewColumn>
这句话是说Binding一个数据源中的Age属性。这里的Path我是省略掉的。这种写法大家要习惯。
再来看一种特殊情况。Path采用.来使用的类型。我们来看看这样的一个小例子。
<Window x:Class="WpfBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib" // 这里我们使用了资源。所以要引用这个命名空间,请注意了。
Title="MainWindow" Height="800" Width="800">
<StackPanel>
<!--定义资源-->
<StackPanel.Resources>
<sys:String x:Key="myResource">
菩提本无树,明镜亦非台。
本来无一物,何处惹尘埃。
</sys:String>
</StackPanel.Resources>
<!--
没有Path的Binding.
1、如果一个数据源本来就是数据,如string,int等。我们可以不用指定Path.
2、如我们下面的写法
-->
<TextBlock x:Name="txtMsg" TextWrapping="Wrap" Text="{Binding Path=.,Source={StaticResource ResourceKey=myResource}}" Margin="5" Background="LightBlue"/>
</StackPanel>
</Window>
这个例子的呈现效果就是。我们看到了资源的信息。会显示出来。
这里的Binding我们还可以写成这样{Binding .,Source={StaticResource ResourceKey=myResource}} 或者{Binding Source={StaticResource ResourceKey=myResource}}
接下来我们来探讨第二个问题。关于数据源的问题。
1.DataContext 这个属性是被定义在FrameworkElement类中的,而这个类是WPF控件的一个基类。所以我们WPF控件都有这个属性。
如果我们在WPF中的某个控件上设置了Path属性,但是没有给定其的Source属性的话。WPF会自动在该控件树上向上查找。把第一个找到的DataContext作为自己的数据源。
2、集合作为数据源的例子。
代码清单如下:
XAML:
<Window x:Class="WpfBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="800" Width="800">
<StackPanel>
<!--DataSource的指定这里采用Grid来做布局-->
<Grid Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="5"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="txtStudentID" BorderBrush="Black" Margin="2"></TextBox>
<ListBox x:Name="lstStudent" BorderBrush="Black" Height="100" Grid.Row="2">
<ListBox.ItemTemplate><!--使用模版来进行数据banding-->
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Id}" Width="100"/>
<TextBlock Text="{Binding Path=Name}" Width="100"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</StackPanel>
</Window>
来看看后台代码
在后台的初始化中添加这段代码。这里有个Member类。该类里面就两个属性。一个是Id,一个是Name.请各位自己添加一个类就好。
List<Member> lstMember = new List<Member>(){
new Member("0001","wy"),
new Member("0002","love"),
new Member("0003","hu"),
new Member("0004","bing"),
new Member("0001","wy")
};
this.lstStudent.ItemsSource = lstMember; // 这里是将我们的数据源给我们的ListBox。关于这点大家应该都很清楚。winform大家应该接触过。
// this.lstStudent.DisplayMemberPath = "Name";
// 主要来看这段代码。这段代码的意思是
// 把我们的ListBox作为我们的数据源。目标是我们的文本框。
// 绑定的对象属性是该数据源中的Id,这里是用的SelectedItem.Id
// 也就是说选中行的Id.从这里我们就清楚了,这个例子不但进行了数据banding。而且还进行选中行的数据Id同其他控件进行关联
// 请大家运行下代码看看效果。
Binding bind = new Binding("SelectedItem.Id") { Source = this.lstStudent };
this.txtStudentID.SetBinding(TextBox.TextProperty, bind);
3.我们再来看另外几个数据源的情况。
XAML:
<Window x:Class="WpfBinding.BindingWin"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BindingWin" Height="600" Width="600">
<StackPanel>
<ListView x:Name="lvStudent" Height="200">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" Width="150" DisplayMemberBinding="{Binding ID}"></GridViewColumn>
<GridViewColumn Header="Name" Width="200" DisplayMemberBinding="{Binding StuName}"></GridViewColumn>
<GridViewColumn Header="Age" Width="220" DisplayMemberBinding="{Binding Age}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<DockPanel>
<Button x:Name="btnFromDataTable" Content="从DataTable获取数据" Click="btnFromList_Click" Width="150"></Button>
<Button x:Name="btnFromXml" Content="从XML中获取数据" Click="btnFromList_Click" Width="150"></Button>
<Button x:Name="btnObjectDataProvider" Content="ObjectDataProvider" Click="ObjectDataProvider_Click" Width="130"></Button>
</DockPanel>
</StackPanel>
</Window>
这几个例子会用到一个辅助类
public class MyStudent {
public string ID { get; set; }
public string StuName { get; set; }
public int Age { get; set; }
public MyStudent(string id,string name,int age)
{
this.ID = id;
this.StuName = name;
this.Age = age;
}
public MyStudent()
{
// TODO: Complete member initialization
}
}
A.来看看DataTable作为数据源的例子
在按钮btnFromDataTable事件中添加如下代码
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(string));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Age", typeof(int));
DataRow row1 = dt.NewRow();
row1["ID"] = "0001";
row1["Name"] = "Wy";
row1["Age"] = 25;
DataRow row2 = dt.NewRow();
row2["ID"] = "0002";
row2["Name"] = "Test121";
row2["Age"] = 24;
DataRow row3 = dt.NewRow();
row3["ID"] = "0003";
row3["Name"] = "Info001";
row3["Age"] = 25;
dt.Rows.Add(row1);
dt.Rows.Add(row2);
dt.Rows.Add(row3);
// 记住这里一定要用DefaultView.请大家注意了。大家可以试验下直接把dt赋值过去的效果。
this.lvStudent.ItemsSource = dt.DefaultView;
/*
以上还有一种写法
this.lvStudent.DataContext = dt;
this.lvStudent.SetBinding(ListView.ItemSourceProperty,New Binding());
使用这种方法。Binding会自动找到DefaultView
*/
B.使用XML文件作为数据源的形式 我这里有个XML文件。我是放在编译目录下的。也就是和我们生成的exe文件在同一个目录。
<?xml version="1.0" encoding="utf-8"?>
<StudentList>
<Student Id="001" Name="Li" Age="25">
</Student>
<Student Id="002" Name="Ming" Age="24">
</Student>
<Student Id="003" Name="Wang" Age="20">
</Student>
<Student Id="004" Name="Hu" Age="25">
</Student>
<Student Id="005" Name="Xiao" Age="24">
</Student>
</StudentList>
后台的代码如下:
// 首先是加载我们的XML文件的内容,然后将这个XDocument文件进行数据的提取
XDocument doc = XDocument.Load(System.AppDomain.CurrentDomain.BaseDirectory + "Xml.xml");
this.lvStudent.ItemsSource = from element in doc.Descendants("Student") // 寻找Student节点
select new MyStudent() {
ID = element.Attribute("Id").Value,
StuName =element.Attribute("Name").Value,
Age = Convert.ToInt32(element.Attribute("Age").Value)
};
这里大家可以尝试着试验下。
还有一种加载XML文件的方式。是这样的。大家看下面一个例子:
<!--
加载XML文件的数据
1、加载xml文件中的数据用Xpath。
2、加载的是属性值的时候用@Id
3、如果加载的是子集元素的值就直接用其标签名
-->
<ListView x:Name="XmlDataSource" >
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding XPath=@Id}" Width="120"></GridViewColumn>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding XPath=Name}" Width="120"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Button x:Name="BtnShowData" Content="显示数据" Click="BtnShowData_Click"></Button>
这里很简单。就是一个显示内容的容器。一个按钮。
这里有点申明。XPath=@Id是说明绑定的是Id这个属性 XPath=Name是说明加载Name节点的内容。这里就是有@和没有@的区别。请大家一定要注意。
我们来看看XML文件的结构:
<?xml version="1.0" encoding="utf-8"?>
<StudentList>
<Student Id="001">
<Name>Wang</Name>
<Age>25</Age>
</Student>
<Student Id="002">
<Name>Yu</Name>
<Age>24</Age>
</Student>
<Student Id="003">
<Name>Zhang</Name>
<Age>20</Age>
</Student>
<Student Id="004">
<Name>Ping</Name>
<Age>25</Age>
</Student>
<Student Id="005">
<Name>Li</Name>
<Age>24</Age>
</Student>
</StudentList>
我们来看看按钮下面是怎么来加载XML文件并且显示在我们的UI上的。
这里给出两种写法:
/* 第一种加载方式
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("MyXml.xml");
XmlDataProvider xp = new XmlDataProvider();
xp.Document = xmlDoc;
// 暴露要绑定的数据
xp.XPath = @"/StudentList/Student";
this.XmlDataSource.DataContext = xp;
this.XmlDataSource.SetBinding(ListView.ItemsSourceProperty, new Binding());
/*第二种加载方式*/
XmlDataProvider xmlPror = new XmlDataProvider();
xmlPror.Source = new Uri(System.AppDomain.CurrentDomain.BaseDirectory+"MyXml.xml");
xmlPror.XPath = @"/StudentList/Student";
this.XmlDataSource.DataContext = xmlPror;
this.XmlDataSource.SetBinding(ListView.ItemsSourceProperty, new Binding());
/*
这里的两种加载。对于XML文件的路径写法是不一样的。这点要注意啊。第一种可以使绝对路径。也可是相对路径。
而第二种是一种URI的形式。
可以看出第二种形式是第一种方式的一种简写。
*/
又到了凌晨了。好了,各位。今天的说明就到这里啊。我们下次再来探讨WPF其他内容。今天就到这里了。各位晚安。美梦。