binding之基本概念
binding之数据源和目标控件
binding 之 Data Convert
DataSource的Property和TargetControl的DependencyProperty绑定,如果两个Property的数据类型不同,则需要转换。
bind.Convert = new DataConverter():IValueConverter
Convert属性的类型是IValueConverter
public interface IValueConverter
{
object Convert(object value, Type outType, object parameter, CultureInfo culture);
object ConvertBack(object value, Type outType, object parameter, CultureInfo culture);
}
Convert用于将数据源属性转换成目标控件属性。
value:数据源属性值
outType:转换后的数据类型
parameter:额外参数
ConvertBack用于将目标控件属性转换成数据源属性。
示例
后台数据源的SexCode,0表示女,1表示男,绑定到TextBlock。
class Sex
{
public int SexCode { get; set; }
}
Sex sex = new Sex();
Binding bind = new Binding();
bind.Source = sex;
bind.Path = new PropertyPath("SexCode");
bind.Converter = new DataConvert();
BindingOperations.SetBinding(tbkSex, TextBlock.TextProperty, bind);
class DataConvert : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int sexCode = (int)value;
if(sexCode == 0)
{
return "女";
}
else
{
return "男";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
示例
使用Binding的ConverterParameter的参数,使DataConvert复用,能被多个binding实例使用。
class Sex
{
public int SexCode { get; set; }
}
class DataConvert : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool usage = (bool)parameter;
if (usage)
{
int sexCode = (int)value;
if (sexCode == 0)
{
return "女";
}
else if (sexCode == 1)
{
return "男";
}
else
{
return "保密";
}
}
else
{
int isCoder = (int)value;
if(isCoder == 0)
{
return false;
}
else if(isCoder == 1)
{
return true;
}
else
{
return null;
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Sex sex = new Sex { SexCode = 3};
Binding bind = new Binding();
bind.Source = sex;
bind.Path = new PropertyPath("SexCode");
bind.Converter = new DataConvert();
bind.ConverterParameter = true;
BindingOperations.SetBinding(tbkSex, TextBlock.TextProperty, bind);
bind = new Binding();
bind.Source = sex;
bind.Path = new PropertyPath("SexCode");
bind.Converter = new DataConvert();
bind.ConverterParameter = false;
cbxIsCoder.SetBinding(System.Windows.Controls.Primitives.ToggleButton.IsCheckedProperty, bind);
![image.png image.png](https://segmentfault.com/img/bVbBcZY)
Binding之Data Invalidation
校验是指改变目标控件的属性,会校验属性的新值,合理则更新数据源,不合理则改变控件的样式进行报错,且不更新数据源。 Binding可以有多个校验规则,一条校验规则是一个继承自抽象类的ValidationRule的类实例。Binding的属性ValidationRules,类型是Collection<ValidationRule>。继承抽象类ValidationRule实现其Validation方法,返回类型是ValidationResult,校验失败,则ValidationResult.IsValid = false;ValidationResult.ErrorContent = "错误信息";校验成功为true和null。
public abstract class ValidationRule
{
protected ValidationRule(ValidationStep validationStep, bool validatesOnTargetUpdated);
public abstract ValidationResult Validate(object value, CultureInfo cultureInfo);
}
public class ValidationResult
{
public ValidationResult(bool isValid, object errorContent);
public static ValidationResult ValidResult { get; }
public object ErrorContent { get; }
public bool IsValid { get; }
}
<TextBox Width="150"
Validation.Error="ItemError">
<TextBox.Text>
<Binding Source="{StaticResource myObject}"
Path="PropertyB"
UpdateSourceTrigger="PropertyChanged"
NotifyOnValidationError="True">
<Binding.ValidationRules>
<src:ValueIsNotNull ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
校验失败,我们需要改变控件样式,来警告或提醒用户,与该情况相关的类是Invalidation。 控件有个Errors属性,类型是Collection<ValidationError>,每个校验规则的返回值的ValidationResult的ErrorContent会填充到该集合。 Invalidation.GetErrors(目标控件)[0].ErrorContent.ToString()能拿到第一条检验失败的错误信息。
三种提醒方式
- 发生错误时,Binding会触发Valiation.ErrorEvent路由事件,沿着目标控件在UI树上向上传播,我们对目标控件或者UI树位置高于目标控件的控件增添路由事件,在路由事件里面,更改控件的外观属性,ToolTip,弹窗等,来提醒出错。
this.AddHandler(Validation.Error,new RoutedEventHandler(this.ErrorHandler)); 或者通过XAML设置 Validation.Error = "ErrorHandler" 2. ToolTip = "{Binding RelativeSource = {RelativeSource self},Path=(Validation.Errors)[0].ErrorContent.ToString}" 3.设置ErrorTemplate。
![image.png image.png](https://segmentfault.com/img/bVbBdF4)
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox x:Name="textText" MinHeight="70" MinWidth="200" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Validation.Error="textText_Error">
<TextBox.Resources>
<local:Student Age="24" x:Key="dataSource"/>
</TextBox.Resources>
<TextBox.Text>
<Binding Source="{StaticResource dataSource}" Path="Age" Mode="TwoWay" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:DataInvalidation ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
</Grid>
多路绑定
|