WPF入门:数据绑定
上一篇我们将XAML大概做了个了解 ,这篇将继续学习WPF数据绑定的相关内容
数据源与控件的Binding
Binding作为数据传送UI的通道,通过INotityPropertyChanged接口的PropertyChanged事件通知Binding数据属性发生改变
public class Product : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
if (PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
通过Binding关联UI控件元素
this.txtOfProduct.SetBinding(TextBox.TextProperty, new Binding() { Path = new PropertyPath("Name"), Source = p });
控件之间的Binding
<TextBox x:Name="TextBox1" Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}"></TextBox>
<Slider x:Name="slider1" Margin="5"></Slider>

我们也可以通过后台C#代码实现
TextBox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "slider1", Mode=BindingMode.OneWay });
统计文本字符长度
<TextBox x:Name="TextBox1" Margin="5" TextWrapping="Wrap" ></TextBox>
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.Length}"></TextBlock>

Binding的Path
Path的索引器方式
<TextBox x:Name="TextBox1" Margin="5" TextWrapping="Wrap" ></TextBox>
<!--获取Text的第三个字符-->
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.[2]}"></TextBlock>
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text[2]}"></TextBlock>
当使用一个集合或者DataView作为Binding源时,如果我们想把它的默认元素作为Path来使用
List<string> names = new List<string>() { "张三", "李四", "王五" };
//张三
this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = names });
//“张三”字符串的长度
this.TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = names,Mode=BindingMode.OneWay});
//获取“张三”字符串中的第1个字符
this.TextBox3.SetBinding(TextBox.TextProperty, new Binding("/[0]") { Source = names, Mode = BindingMode.OneWay });
如果集合中嵌套集合,我们依然可以通过多级"/"语法把子集作为Path的元素
class City
{
public string Name { get; set; }
}
class Province
{
public List<City> Citys { get; set; }
public string Name { get; set; }
}
class Country
{
public List<Province> Provinces { get; set; }
public string Name { get; set; }
}
TextBox1.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source = countries });
TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Name") { Source = countries });
TextBox3.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Citys/Name") { Source = countries });

省略Path
sys需要引用xmlns:sys="clr-namespace:System;assembly=mscorlib"
<StackPanel.Resources>
<sys:String x:Key="text">
WPF入门手册
</sys:String>
</StackPanel.Resources>
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding .,Source={StaticResource ResourceKey=text}}" ></TextBox>
TextBox2.SetBinding(TextBox.TextProperty, new Binding(".") { Source = "WPF技术入门" });
没有Path和Source,Binding可以通过DataContext获取数据
<StackPanel.DataContext>
<sys:String>
WPF入门手册
</sys:String>
</StackPanel.DataContext>
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding Mode=OneWay}" ></TextBox>
选中ListBox元素显示对应的属性的一个例子
<TextBox x:Name="TextBox1" Margin="5" ></TextBox>
<ListBox x:Name="ListBox1"></ListBox>
List<City> cities = new List<City>() {
new City() { Id=1,Name="北京" },
new City() { Id=2,Name="昆明" },
new City() { Id=3,Name="上海" },
new City() { Id=4,Name="厦门" },
new City() { Id=5,Name="广州" }
};
this.ListBox1.ItemsSource = cities;
this.ListBox1.DisplayMemberPath = "Name";
this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = this.ListBox1 });

使用Binding的RelativeSource
当Binding有明确的数据源的时,我们可以通过Soure或ElementName赋值办法关联Binding,但有事我们不知道Soure对象的名字是什么,却知道它与作为Binding目标对象的UI元素布局上的相对关系,通过RelativeSourceMode枚举设置关联的对象关系
<Grid x:Name="g1">
<StackPanel x:Name="s1">
<DockPanel x:Name="d1">
<TextBox x:Name="TextBox1" Margin="5" ></TextBox>
</DockPanel>
</StackPanel>
</Grid>
后台代码处理
RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor)
{
AncestorLevel = 1,
AncestorType = typeof(StackPanel)
};
//将StackPanel的Name s1赋给了TextBox1的Text
TextBox1.SetBinding(TextBox.TextProperty, new Binding("Name") { RelativeSource = rs });
也可以通过XAML的方式赋值
<Grid x:Name="g1">
<StackPanel x:Name="s1">
<DockPanel x:Name="d1">
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel},AncestorLevel=1,Mode=FindAncestor}, Path=Name}" ></TextBox>
</DockPanel>
</StackPanel>
</Grid>
Binding数据验证
Binding的ValidationRules属性的类型为Collection<ValidationRule>。通过实现Validate方法返回给ValidationResult对象,并设置IsVaild属性,ErrorContent属性可以接受一个字符串。
public class RangValidationRule : ValidationRule
{
//验证数据
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
double d = 0;
if (double.TryParse(value.ToString(), out d))
{
if (d >= 1 && d <= 100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "数据错误");
}
}
<TextBox x:Name="TextBox1" Margin="5"></TextBox>
<Slider x:Name="slider1" Minimum="1" Maximum="100" Margin="5"></Slider>
Binding binding = new Binding("Value") {
Source=slider1,
UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged,
};
binding.ValidationRules.Add(new RangValidationRule());
this.TextBox1.SetBinding(TextBox.TextProperty, binding);

显示错误提示
public MainWindow()
{
InitializeComponent();
Binding binding = new Binding("Value")
{
Source = slider1,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
NotifyOnValidationError = true//开启错误通知
};
binding.ValidationRules.Add(new RangValidationRule());
this.TextBox1.SetBinding(TextBox.TextProperty, binding);
//注册验证错误事件
this.TextBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationErrorNotify));
}
private void ValidationErrorNotify(object sender, RoutedEventArgs e)
{
var errors = Validation.GetErrors(this.TextBox1);
if (errors.Count > 0)
{
TextBlock1.Text = errors[0].ErrorContent.ToString();
}
}

多路Binding
一般我们在做注册用户功能的时候,输入密码的时候都需要再确认输入密码,比较两次输入是否一致,现在我们可以通过多路Binding来简单的实现这个功能
首先实现一个IMultiValueConverter接口功能,如果两次密码一致,提交按钮状态为可用
public class SubmitMultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return (!values.Cast<string>().Any(a => string.IsNullOrEmpty(a))/*验证所有元素非空*/ &&
values[0].ToString() == values[1].ToString())/*值1=值2*/;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML代码
<TextBox x:Name="Password" Margin="5"></TextBox>
<TextBox x:Name="Passworder" Margin="5"></TextBox>
<Button x:Name="Submit" Content="提交" Margin="10" Height="30" Width="100"></Button>
后台Binding
Binding pwdBinding = new Binding("Text") { Source = Password };
Binding pwderBinding = new Binding("Text") { Source = Passworder };
MultiBinding multi = new MultiBinding() { Mode=BindingMode.OneWay};
multi.Bindings.Add(pwdBinding);
multi.Bindings.Add(pwderBinding);
multi.Converter = new SubmitMultiBindingConverter();
Submit.SetBinding(Button.IsEnabledProperty, multi);

以上就是Binding常用到的功能,下篇我将继续学习依赖属性和WPF路由事件的相关内容
WPF入门:数据绑定的更多相关文章
- WPF入门教程系列十五——WPF中的数据绑定(一)
使用Windows Presentation Foundation (WPF) 可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能.WPF的数据绑定跟Winform与ASP.NET中的数 ...
- WPF入门教程系列二十三——DataGrid示例(三)
DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...
- WPF入门教程系列三——Application介绍(续)
接上文WPF入门教程系列二——Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...
- WPF入门教程系列二——Application介绍
一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只 ...
- WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...
- WPF入门教程系列(一) 创建你的第一个WPF项目
WPF入门教程系列(一) 创建你的第一个WPF项目 WPF基础知识 快速学习绝不是从零学起的,良好的基础是快速入手的关键,下面先为大家摞列以下自己总结的学习WPF的几点基础知识: 1) C#基础语法知 ...
- WPF入门教程系列一
WPF入门教程 一. 前言 公司项目基于WPF开发,最近项目上线有点空闲时间写一篇基于wpf的基础教材,WPF也是近期才接触,学习WPF也是在网上查资料与微软的MSDN进行学习,写本博客的目为了温 ...
- WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush)
原文:WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush) 前面我们提到了LinearGradientBrush可以用来画渐变填充图,那么我们同时也可以使用ImageBr ...
- WPF入门(四)->线形区域Path内容填充之渐变色(LinearGradientBrush)
原文:WPF入门(四)->线形区域Path内容填充之渐变色(LinearGradientBrush) 前面我们介绍到,Path对象表示一个用直线或者曲线连接的图形,我们可以使用Path.Data ...
随机推荐
- .NET Core采用的全新配置系统[10]: 配置的同步机制是如何实现的?
配置的同步涉及到两个方面:第一,对原始的配置文件实施监控并在其发生变化之后从新加载配置:第二,配置重新加载之后及时通知应用程序进而使后者能够使用最新的配置.要了解配置同步机制的实现原理,先得从认识一个 ...
- 用原生js做单页应用
最近在公司接到一个需求,里面有一个三级跳转.类似于选择地址的时候,选择的顺序是:省份->市->区.如果分三个页面跳转,那么体验非常不好,如果引入其他框架做成单页应用,又比较麻烦.所以可以用 ...
- node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法
1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...
- [原] KVM 虚拟化原理探究(2)— QEMU启动过程
KVM 虚拟化原理探究- QEMU启动过程 标签(空格分隔): KVM [TOC] 虚拟机启动过程 第一步,获取到kvm句柄 kvmfd = open("/dev/kvm", O_ ...
- css常用hack
原文地址:css常用hack 突然想起今天早上在CNZZ看到的统计数据,使用IE6.7的用户比例还真多,看到之后我的心都碎了.微软都放弃了为毛还有这么多人不死心? 所以说,IE下的兼容还是得做的. – ...
- ResponsibleChain(责任链模式)
/** * 责任链模式 * @author TMAC-J * 老板讲任务交给CTO,CTO自然不会亲自去做,又把人物分配给项目经理,项目经理再把任务分配给组长,组长再分配给个人 * 如果中途哪个环节出 ...
- 浏览器的兼容模式下的button中文字垂直方向不居中显示
<button style="cursor:pointer;vertical-align: middle;" >删除</button> 这时候垂直不居中. ...
- 微信开发笔记(accesstoken)
access_token分两种 一种是公众号权限获取用,调用cgi-bin接口 ,此种token一个公众号同时只有一个,用这一个就够了. 服务器最好缓存. 用这个token前提是用户关注了此公众号. ...
- iOS之ProtocolBuffer搭建和示例demo
这次搭建iOS的ProtocolBuffer编译器和把*.proto源文件编译成*.pbobjc.h 和 *.pbobjc.m文件时,碰到不少问题! 搭建pb编译器到时没有什么问题,只是在把*.pro ...
- centos 6 安装配置openvpn
下载地址:http://swupdate.openvpn.org/community/releases/http://www.oberhumer.com/opensource/lzo/download ...