WPF 基础 - Binding 的源与路径
1. 源与路径
- 把控件作为 binding 源与 binding 标记拓展;
- 控制 Binding 的方向及数据更新;
- Binding 的路径 Path;
- 没有路径的 Binding;
- 为 Binding 指定源的几种方法;
- 没有 Source 的 Binding;
- 使用集合对象作为列表控件的 ItemsSource;
- 使用 ADO.NET 对象作为 Binding 的源;
- 使用 XML 的数据作为 Binding 的源;
- 使用 LINQ 的检索结果作为 Binding 的源:
- 使用 ObjectDataProvider 对象作为 Binding 的 Source;
- 使用 Binding 的 RelativeSource;
Binding 作为数据的桥梁,两端分别是源 (Source) 和目标 (Target),同时 Target 作为对象可能会有多个属性值,通过 路径 (Path) 指定通过 Binding 送达 UI 元素的属性;
source:可以为集合对象、ADO.NET 对象、XML 数据、LINQ 检索结果、ObjectDataProvider 对象等;
1.1 把控件作为 binding 源与 binding 标记拓展
<Slider x:Name="slider" Maximum="100" Minimum="0"/>
<TextBlock x:Name="textBlock" Text="{Binding ElementName=slider, Path=Value}"/>
<!--Binding 构造器本身接收 Path 作为参数,因此-->
<TextBlock x:Name="textBlock" Text="{Binding Value, ElementName=slider}"/>
//等价于后台:
this.textBlock.SetBinding(TextBlock.TextProperty, new Binding("Value") { ElementName = "slider" });
1.2 控制 Binding 的方向及数据更新
Binding 的属性 Mode 的枚举值决定 Binding 的更新方向:
- OneWay
- OneWayToSource
- OneTime
- TwoWay
- Default :不同控件的默认值不一样,比如文本框和复选框默认双向绑定,TextBlock 单向
Binding 的属性 UpdateSourceTrigger 的枚举值决定 Binding 的触发数据更新的条件:
- Explicit :调用 System.Windows.Data.BindingExpression.UpdateSource 方法时才更新
- PropertyChanged
- LostFocus
- Default : 大多数默认值是 PropertyChanged,而 System.Windows.Controls.TextBox.Text 是 LostFocus
NotifyOnSourceUpdated、NotifyOnTargetUpdated bool值
当值从绑定目标传输到绑定源时是否引发 System.Windows.Data.Binding.SourceUpdated 事件;
当值从绑定源传输到绑定目标时是否引发 System.Windows.Data.Binding.TargetUpdated 事件。
如下面例子:修改 slider 的值,引发 TargetUpdated 事件;
修改 textBox 的值,引发 SourceUpdated 事件;可以记录。
<TextBox x:Name="textBlox"
TargetUpdated="textBlock_TargetUpdated"
SourceUpdated="textBlock_SourceUpdated"
Text="{Binding Path=Value, ElementName=slider, UpdateSourceTrigger=PropertyChanged,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"/>
1.3 Binding 的路径 Path
除了上面所说,还支持多级路径
<TextBox x:Name="textBox2" Text="{Binding Path=Text.Length, ElementName=textBox, Mode=OneWay}"/>
//等价于:
this.textBox2.SetBinding(TextBox.TextProperty, new Binding("Text.Length") { Source = this.textBox, Mode = BindingMode.OneWay });
<TextBox x:Name="textBox2" Text="{Binding Path=Text.[3], ElementName=textBox, Mode=OneWay}"/>
List<string> stringList = new List<string>() { "Bob", "Long" };
this.xx1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = stringList });//Bob
this.xx2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = stringList, Mode = BindingMode.OneWay });//3
this.xx3.SetBinding(TextBox.TextProperty, new Binding("/[2]") { Source = stringList, Mode = BindingMode.OneWay });//b
1.4 没有路径的 Binding
比如 int,string 等本身就是数据,因此用 Path=. 来表示,在 xaml 中可以省略,在 C# 中不能省略
<Window.Resources>
<sys:String x:Key="myString">悟空的小脾气</sys:String>
</Window.Resources>
<TextBlock Text="{Binding Path=., Source={StaticResource myString}}"/>
<TextBlock Text="{Binding ., Source={StaticResource myString}}"/>
<TextBlock Text="{Binding Source={StaticResource myString}}"/>
<TextBlock x:Name="knowNull"/>
this.knowNull.SetBinding(TextBlock.TextProperty, new Binding(".") { Source = this.FindResource("myString")});
// 4 个 TextBlock 都展示 "悟空的小脾气"
1.5 没有 Source 的 Binding
1.5.1 无 Source 的 Binding
当一个 Binding 只知道自己的 Path,而不知自己的 Source 时,会沿着 UI 元素树一层一层树的根部找过去,直到找到有设置 DataContext 的元素。
<Window ..>
<StackPanel>
<StackPanel.DataContext>
<local:Student Id="6" Age="20"/>
</StackPanel.DataContext>
<Grid>
<StackPanel>
<TextBlock Text="{Binding Id}" />
<TextBlock Text="{Binding Age}" />
</StackPanel>
</Grid>
</StackPanel>
</Window
1.5.2 无 Path 无 Source 的 Binding
<Window ..>
<StackPanel>
<StackPanel.DataContext>
<sys:String>Hello~</sys:String>
</StackPanel.DataContext>
<Grid>
<StackPanel>
<TextBlock Text="{Binding}" />
</StackPanel>
</Grid>
</StackPanel>
</Window
1.5.3 测试 DataContext 往下传递
<Grid>
<Grid.DataContext>
<local:Student Id="1000" Age="100"></local:Student>
</Grid.DataContext>
<StackPanel>
<StackPanel.DataContext>
<local:Stu Id="6" Play="ball"></local:Stu>
</StackPanel.DataContext>
<TextBlock Text="{Binding Id}"/>
<TextBlock Text="{Binding Play}"/>
<TextBlock Text="{Binding Age}"/>
</StackPanel>
</Grid>
// 6
// ball
// (空)
把 StackPanel 的 DataContext 去掉
// 1000
// (空)
// 100
1.6 使用集合对象作为列表控件的 ItemsSource
- 当我们没有为 ListBox 的 ItemTemplate 指定 DataTemplate 时,
ListBox 在获得 ItemsSource 后会创建等量的 ListBoxItem 并自动设置 DataTemplate。 - 在获取 DataTemplate 的过程中会以 DisplayMemberPath 属性值作为 Path 创建 Binding。
- Binding 的目标是 ListBoxItem 的内容插件(TextBox)
1.7 使用 ADO.NET 对象作为 Binding 的源
<ListBox x:Name="listbox" DisplayMemberPath="Id" ItemsSource={Binding dataView}></ListBox>
<ListView x:Name="listview" ItemsSource={Binding dataView}>
<ListView.View>
<GridView>
<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}" Width="100"/>
<GridViewColumn Header="CameraEncode" DisplayMemberBinding="{Binding CameraEncode}" Width="100"/>
<GridViewColumn Header="Pan" DisplayMemberBinding="{Binding Pan}" Width="100"/>
</GridView>
</ListView.View>
</ListView>
DataView dataView {get;set;}//再添加更新通知。
System.Data.DataTable dt = this.Load();
dataView = dt.DefaultView;
并不能展示数据,但行数是正确的。
1.8 使用 XML 的数据作为 Binding 的源
前面提 x:XData 时有实现过一次 ListBox 绑定到 XmlDataProvider 的方式;
<ListBox x:Name="listbox" Grid.Row="5" I
temsSource="{Binding Source={StaticResource XMlData}, XPath=/Super/Colors/Color}"/>
这次提供 C# 版;
XmlDataProvider xdp = new XmlDataProvider();
xdp.Source = new Uri(@"D:\RawData.xml");
xdp.XPath = @"/StudentList/Student";
this.listbox.DataContext = xdp;
this.listbox.SetBinding(ListView.ItemsSourceProperty, new Binding());
设置 XmlDataProvider.Source 的效果等同于 XmlDataProvider.Document:
xdp.Source = new Uri(@"D:\RawData.xml");
=
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(@"D:\RawData.xml");
xdp.Document = doc;
1.9 使用 LINQ 的检索结果作为 Binding 的源
1.9.1 LINQ from List
<ListView x:Name="listViewStrs" Height="100" Margin="100">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="60" DisplayMemberBinding="{Binding Id}" />
<GridViewColumn Header="Name" Width="60" DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>
...
List<Student> listStr = new List<Student>()
{
new Student() { Id = "11", Name = "YaoMing"},
new Student() { Id = "24", Name = "Kobe"},
new Student() { Id = "8", Name = "Kobe-Young"},
};
listViewStrs.ItemsSource = from str in listStr where str.Name.StartsWith("K") select str;
1.9.2 LINQ + XML
listbox.ItemsSource =
from element in xdoc.Descendants("Student")
where element.Attribute("Name").Value.StartsWith("T")
select new Student()
{
Id = int.Parse(element.Attribute("Id").Value),
Name = element.Attribute("Name").Value
};
1.9.3 LINQ + DataTable
listbox.ItemsSource =
from row in dt.Row.Cast<DataRow>()
where Convert.ToString(row["Name"]).StartsWith("T")
select new Student()
{
Id = int.Parse(row["Id"].ToString()),
Name = row["Name"].ToString()
};
1.10 使用 ObjectDataProvider 对象作为 Binding 的 Source
1.10.1 介绍一波 ObjectDataProvider
class Calculator
{
public string Add(string arg1, string arg2)
{
double x = 0;
double y = 0;
double z = 0;
if (double.TryParse(arg1, out x) && double.TryParse(arg2, out y))
{
z = x + y;
return z.ToString();
}
return "Input Error";
}
}
ObjectDataProvider dp = new ObjectDataProvider();
dp.ObjectInstance = new Calculator();
dp.MethodName = "Add";
dp.MethodParameters.Add("10");
dp.MethodParameters.Add("15");
MessageBox.Show(dp.Data.ToString()); // 25
1.10.2 使用 ObjectDataProvider 作为 Binding 的 Source
<StackPanel Grid.Row="10">
<TextBox x:Name="textBlockArg1"/>
<TextBox x:Name="textBlockArg2"/>
<TextBox x:Name="textBlockResult"/>
</StackPanel>
ObjectDataProvider dp = new ObjectDataProvider();
dp.ObjectInstance = new Calculator();
dp.MethodName = "Add";
dp.MethodParameters.Add("0");
dp.MethodParameters.Add("0");
Binding bindingToArg1 = new Binding("MethodParameters[0]")
{
Source = dp,
BindsDirectlyToSource = true,//告诉Binding对象只负责把从UI得到的数据写入Source(odp)而不是写入odp对象包装的Calculator对象中,默认 false
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding bindingToArg2 = new Binding("MethodParameters[1]")
{
Source = dp,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding bindingToResult = new Binding(".") { Source = dp };
this.textBlockArg1.SetBinding(TextBox.TextProperty, bindingToArg1);
this.textBlockArg2.SetBinding(TextBox.TextProperty, bindingToArg2);
this.textBlockResult.SetBinding(TextBox.TextProperty, bindingToResult);
1.11 使用 Binding 的 RelativeSource
<Grid x:Name="g3">
<Grid x:Name="g2">
<Grid x:Name="g1">
<StackPanel x:Name="s2">
<StackPanel x:Name="s1">
<TextBox x:Name="textBlock1"/>
<TextBox x:Name="textBlock2"/>
<TextBox x:Name="textBlock3"/>
<TextBox x:Name="textBlock4"/>
<TextBox x:Name="textBlock5" Text="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1,AncestorType={x:Type StackPanel}}}"/>
<TextBox x:Name="textBlock6" Text="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=2,AncestorType={x:Type StackPanel}}}"/>
<TextBox x:Name="textBlock7" Text="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=3,AncestorType={x:Type Grid}}}"/>
<TextBox x:Name="textBlock8" Text="{Binding Name, RelativeSource={RelativeSource Mode=Self}}"/>
</StackPanel>
</StackPanel>
</Grid>
</Grid>
</Grid>
RelativeSource rs = new RelativeSource();
rs.AncestorLevel = 1;
rs.AncestorType = typeof(StackPanel);
Binding binding = new Binding("Name") { RelativeSource = rs };
this.textBlock1.SetBinding(TextBox.TextProperty, binding);
RelativeSource rs2 = new RelativeSource();
rs2.AncestorLevel = 2;
rs2.AncestorType = typeof(StackPanel);
Binding binding2 = new Binding("Name") { RelativeSource = rs2 };
this.textBlock2.SetBinding(TextBox.TextProperty, binding2);
RelativeSource rs3 = new RelativeSource();
rs3.AncestorLevel = 3;
rs3.AncestorType = typeof(Grid);
Binding binding3 = new Binding("Name") { RelativeSource = rs3 };
this.textBlock3.SetBinding(TextBox.TextProperty, binding3);
RelativeSource rs4 = new RelativeSource();
rs4.Mode = RelativeSourceMode.Self;
Binding binding4 = new Binding("Name") { RelativeSource = rs4};
this.textBlock4.SetBinding(TextBox.TextProperty, binding4);
// s1
// s2
// g3
// textblock4
// s1
// s2
// g3
// textblock8
从 textBlock3.Text 展示的是 "g3",可以看出 RelativeSource.AncestorLevel 表示从自身开始,往根结点方向找父节点,找第 x 个 AncestorType 的元素;
如果是找自身,就用 RelativeSource.Mode = RelativeSourceMode.Self;
RelativeSource 有三个静态属性:PreviousData、Self、TemplateParent,分别对应 RelativeSourceMode 的三个同名称的枚举值,在 DataTemplate 中常用到,通过 ILSpy 可以看到源代码:
public static RelativeSource TemplatedParent
{
get
{
if (s_templatedParent == null)
{
s_templatedParent = new RelativeSource(RelativeSourceMode.TemplatedParent);
}
return s_templatedParent;
}
}
WPF 基础 - Binding 的源与路径的更多相关文章
- 深入浅出-Binding的源与路径
1.把控件作为Binding源与Binding标记扩展<TextBox x:Name="textBox1" Text="{Binding Path=Value, E ...
- Binding的源与路径
1.把控件作为Binding的源 例子:拖动Slider,输入框中的值也会跟着改变,或在输入框中输入数值,滑动条也会自动移动 <Window x:Class="把控件作为Binding ...
- WPF基础篇之资源文件路径
WPF资源文件的路径 关于WPF资源文件的路径 这几天在WPF中调用资源文件的Uri时,因为是在代码里调用Uri写的Uri总是不对,要么运行直接报异常,要么说找不到资源文件.下面是我解决的整个经过和碰 ...
- WPF 基础 - Binding 对数据的转换和校验
1. Binding 对数据的转换和校验 Binding 中,有检验和转换关卡. 1.1 数据校验 源码: namespace System.Windows.Data { public class B ...
- WPF 基础 - Binding 的 数据更新提醒
WPF 作为一个专门的展示层技术,让程序员专注于逻辑层,让展示层永远处于逻辑层的从属地位: 这主要因为有 DataBinding 和配套的 Dependency Property 和 DataTemp ...
- WPF之Binding深入探讨
原文:http://blog.csdn.net/fwj380891124/article/details/8107646 1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在 ...
- WPF的Binding功能解析
1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在存储.逻辑和界面三层之间流通,所以站在数据的角度上来看,这三层都很重要.但算法在3层中的分布是不均匀的,对于一个3层结构的 ...
- WPF之Binding深入探讨--Darren
1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在存储.逻辑和界面三层之间流通,所以站在数据的角度上来看,这三层都很重要.但算法在3层中的分布是不均匀的,对于一个3层结构的 ...
- WPF之Binding【转】
WPF之Binding[转] 看到WPF如此之炫,也想用用,可是一点也不会呀. 从需求谈起吧: 首先可能要做一个很炫的界面.见MaterialDesignInXAMLToolKit. 那,最主要的呢, ...
随机推荐
- 自动化将 word 转为 pdf,再将pdf转为图片!
参考: https://blog.csdn.net/ynyn2013/article/details/49120731 https://www.jianshu.com/p/f57cc64b9f5e 一 ...
- Shpfile文件的字段类型说明
Shpfile文件的字段类型设置如下表所示: 字段类型 字符 字段长度 长整型 N 9 短整型 N 4 浮点型 F 13 双精度 F 19 文本 C 50 特别需要注意的是字段长度,在导出SHP的时候 ...
- 一篇文章图文并茂地带你轻松学会 HTML5 storage
html5 storage api localStorage 和 sessionStorage 是 html5 新增的用来存储数据的对象,他们让我们可以以键值对的形式存储信息. 为什么要有 stora ...
- 牛客网多校第5场 I vcd 【树状数组+离散化处理】【非原创】
题目:戳这里 学习博客:戳这里 作者:阿狸是狐狸啦 n个点,一个点集S是好的,当且仅当对于他的每个子集T,存在一个右边无限延长的矩形,使的这个矩形包含了T,但是和S-T没有交集. 求有多少个这种集合. ...
- Git使用指南(下)
9 初识分支 把每一次的提交,都用线连起来,你会发现,很连贯. C/C++ 指针的概念 git reset --hard commitid HEAD 如果说内容已经add到暂存区,此时要想 ...
- sdut2879 枚举起点DP
这个题和乌龟棋之类的DP差不多要学会缩减状态 就是,,我们只需枚举当前这个人是谁,选什么颜色,A用了多少,B用了多少 C用了多少我们就不用枚举了,知道选了多少人,A,B用了多少,你还不知C用了多少么, ...
- React Fragment All In One
React Fragment All In One React还提供了一个无需包装即可呈现多个元素的组件. https://reactjs.org/docs/react-api.html#fragme ...
- 编程术语 All In One
编程术语 All In One js 名词,术语 函数 函数签名 一个函数签名 (或类型签名,或方法签名) 定义了 函数 或 方法 的输入与输出. 一个签名可以包括: 参数 及参数的 类型 一个返回值 ...
- HTTPS All In One
HTTPS All In One HTTPS & web security HTTPS Hypertext Transfer Protocol Secure HTTPS is an exten ...
- React vs Vue in 2020
React vs Vue in 2020 技术选型 React // UserProfile.jsx function UserProfile({id, showAvatar, onFollowCli ...