绑定可以是单向的或双向的。数据绑定的源可以是普通的 .NET 属性或 Dependency 属性,但目标属性必须是Dependency属性。
在WinForm中,我们要想对控件赋值,需要在后台代码中拿到控件对象进行操作,这种赋值形式,从根本上是无法实现界面与逻辑分离的。
在WPF中,微软引入了Binding对象,通过Binding,我们可以直接将控件与数据做绑定,在后台不用拿到控件对象,直接操作数据源,系统会自动监听数据源的变化实时的更新到控件上,相反的,用户改变控件的值,也会实时更新到后台数据源,这也就是我们之前所说的,WPF天生支持MVVM模式。
命令是MVVM模式实现的重要一环,
命令(Command)
模板(Template)、
数据绑定(Binding)
一起构成了WPF中的主要三个核心要素,其中模板实现了WPF灵活的控件自定义(UI),数据绑定实现了前后端的数据分离、命令则实现了前后端的逻辑分离。
》》》 前端绑定
》》后端绑定
》》数据校验
》》》自定义一个校验规则,继承ValidationRule抽象类
public class ZenValidationRule: ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value == null)
return new ValidationResult(false, "不能为空!");
if (value as string != "Ares")
return new ValidationResult(false, "必须是Ares");
return new ValidationResult(true, null);
}
}
public MainWindow()
{
InitializeComponent();
Binding bd = new Binding() { Path = new PropertyPath("Text"), Source = this.txt1 };
ZenValidationRule vd = new ZenValidationRule();
vd.ValidatesOnTargetUpdated = true;
bd.ValidationRules.Add(vd);
bd.NotifyOnValidationError = true;
this.txt2.SetBinding(TextBox.TextProperty, bd);
//添加一个路由事件 触发的条件 是发送错误【Validation.ErrorEvent】
this.txt2.AddHandler(Validation.ErrorEvent,new RoutedEventHandler(this
.VadidatingError));
}
private void VadidatingError(object sender, RoutedEventArgs e)
{
if (Validation.GetErrors(this.txt2).Count>0)
{
this.txt2.ToolTip = Validation.GetErrors(this.txt2)[0].ErrorContent.ToString();
}
}
《《通过静态属性Validation.Errors可以获得控件对象中所捕获到的所有校验异常集合,再通过集合中元素对象的ErrorContent属性就能获得校验异常中的异常信息。
》》》数据转换
public class DateConverter : IValueConverter
{
//当值从绑定源传给绑定目标(到View) 触发 该方法
//parameter 是 ConverterParameter 传的值
// Text="{Binding ElementName=date1, Path=SelectedDate, Converter={StaticResource cvtDate},ConverterParameter=xx}"
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return DependencyProperty.UnsetValue;
}
DateTime date = (DateTime)value;
return date.ToString("yyyy-MM-dd");
}
//当值从绑定目标传递给绑定源时(数据),触发此方法
//parameter 是 ConverterParameter 传的值
// Text="{Binding ElementName=date1, Path=SelectedDate, Converter={StaticResource cvtDate},ConverterParameter=xx}"
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string date = value as string;
DateTime txtDate;
if (DateTime.TryParse(date, out txtDate))
{
return txtDate;
}
return DependencyProperty.UnsetValue;
}
}
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:DateConverter x:Key="cvtDate"></local:DateConverter>
</Window.Resources>
<StackPanel>
<DatePicker x:Name="date1" SelectedDateFormat="Short"></DatePicker>
<TextBox x:Name="txt1" Height="50" Width="100"
Text="{Binding ElementName=date1, Path=SelectedDate, Converter={StaticResource cvtDate}}"></TextBox>
<Label Content="{Binding ElementName=date1, Path=Text}"></Label>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace WpfDemo.Converter
{
public class ConverterHelper : IValueConverter
{
///
/// 从源数据(ViewModel)——》目标(View界面)
///
/// 源数据的值
///
/// 目标传递的值
///
///
///
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
{
return false;
}
else
{
return value.ToString() == parameter.ToString();
}
}
///
/// 从目标元素——》源数据(ViewModel)
///
/// 源数据的值
///
/// 目标传递的值
///
///
///
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return parameter;
}
}
}
<Window x:Class="WpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfDemo"
xmlns:cnt="clr-namespace:WpfDemo.Converter"
mc:Ignorable="d"
Title="XXX" Height="650" Width="650"
WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<cnt:ConverterHelper x:Key="cnt_general"></cnt:ConverterHelper>
<ControlTemplate TargetType="RadioButton" x:Key="rbtn">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Height="20" Width="20" CornerRadius="10" Background="Red">
<Border x:Name="bod" Height="15" Width="15" CornerRadius="7" Background="Yellow" Visibility="Hidden"></Border>
</Border>
</Grid>
<ControlTemplate.Triggers >
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" Value="Visible" TargetName="bod"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="200"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<StackPanel>
<TextBlock Text="男"></TextBlock>
<RadioButton Template="{StaticResource rbtn}"
IsChecked="{Binding General,Converter={StaticResource cnt_general},ConverterParameter=1}"
>
</RadioButton>
</StackPanel>
<StackPanel Grid.Row="1" >
<TextBlock Text="女"></TextBlock>
<RadioButton Template="{StaticResource rbtn}"
IsChecked="{Binding General,Converter={StaticResource cnt_general},ConverterParameter=2}"
>
</RadioButton>
</StackPanel>
</Grid>
</Window>