WPF 属性值绑定、转换
TextBlock绑定属性
绑定集合中的第一项的属性
<TextBlock Text="{Binding [1].PropertyName1}" DataContext="{Binding DemoList}"/>
绑定单个属性及转换器
<UserControl.Resources>
<cvt:StateConv x:Key="stateConv"/>
</UserControl.Resources>
...
<TextBlock Text="{Binding Name, StringFormat={}{0:F2}, Converter="{StaticResource stateConv}"}"/>
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
public class StateConv: IValueConverter
{
// 此文本将显示在控件中(比如:TextBox)
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int type = 0;
if (int.TryParse(value.ToString(), out type))
{
if (type == 1) { return "正常"; }
else { return "异常"; }
}
return DependencyProperty.UnsetValue;
}
// 目标数据格式转换为原数据格式(正常->1)
// 当您更改控件TextBox的值时,ConvertBack方法将在绑定再次触发时调用(默认OnFocusLost)
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (string.IsNullOrEmpty(value?.ToString()))
return -1;
var item = TypeResource.FirstOrDefault(x => x.DisplayText == value.ToString());
if (item == null)
{
return -1;
}
return item.Key;
}
}
转换器2
数值转换,显示指定枚举类型的文本描述
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && int.TryParse(value.ToString(), out int type))
{
if (Enum.IsDefined(typeof(PropertyNameEnumType), type))
{
var @enum = (PropertyNameEnumType)type;
return @enum.GetEnumDescription();
}
}
return "未知状态";
}
多重绑定1
<Label.Content>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}({1})">
<Binding Path="Name1" TargetNullValue="用默认值来显示为空的字段" />
<Binding Path="Name2" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Label.Content>
StringFormat要求它的目标是string类型。 可在指定控件内嵌套TextBlock进行自定义格式转换。
若要体现动态数据,属性所属类需要实现INotificationPropertyChanged接口,绑定的属性可以响应属性更改事件。
多重绑定2
<UserControl.Resources>
<cvt:MultiStateConv x:Key="multiStateConverter"/>
<cvt:MultiVersionTypeConv x:Key="multiVersionTypeConverter"/>
</UserControl.Resources>
...
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource multiStateConverter}" ConverterParameter="{StaticResource bindingProxy}">
<Binding Path="Name"/>
<Binding Path="Name2"/>
<!--绑定父级属性 PropertyName2-->
<Binding Path="DataContext.PropertyName2" RelativeSource="{RelativeSource AncestorLevel=2, AncestorType={x:Type ListBoxItem}}"/>
</MultiBinding>
</TextBlock.Content>
</TextBlock>
<DataGridTextColumn Header="版本类型" Width="*">
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource multiVersionTypeConverter}" ConverterParameter="{StaticResource multiStateConverter}">
<Binding Path="Type1"/>
<Binding Path="Type2"/>
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
using System;
using System.Globalization;
using System.Windows.Data;
[ValueConversion(typeof(object[]), typeof(string))]
class MultiStateConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var cvt = parameter as MultiStateConv;
string rslt = string.Empty;
if (int.TryParse(values[0].ToString(), out int type))
{
//...
}
if (int.TryParse(values[1].ToString(), out int type2))
{
//...
}
return rslt;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
多重绑定3
当传递的参数过多时,可以使用绑定代理。
当显示逻辑比较复杂时,有多个参数规则,可重复设置同样内容,并控制不同的显隐来实现。
xmlns:cvt="clr-namespace:ProjectName.Converters"
<Color x:Key="Color1">#FF4E5E</Color>
<SolidColorBrush x:Key="Brush1" Color="{DynamicResource Color1}"/>
<cvt:BindingProxy x:Key="bindingProxy" Data="{DynamicResource Brush1}" Reserve="{DynamicResource 3thDllBrush}" Thread="10.0"/>
<cvt:ExceptionValueConv x:Key="exceptionValueConveter"/>
<cvt:ExceptionForegroundVisibleConv x:Key="exceptionForegroundVisibleConveter"/>
<cvt:ExceptionForegroundReVisibleConv x:Key="exceptionForegroundReVisibleConveter"/>
<Grid>
<TextBlock Foreground="{DynamicResource Brush3}"
Visibility="{Binding Percent, Converter={StaticResource exceptionForegroundVisibleConveter}, ConverterParameter={StaticResource bindingProxy}}">
<Run Text="{Binding Percent, StringFormat={}{0:f1}, Converter={StaticResource exceptionValueConveter}}" />
<Run Text="%"/>
</TextBlock>
<!--同样内容-->
<TextBlock Foreground="{DynamicResource Brush4}"
Visibility="{Binding Percent, Converter={StaticResource exceptionForegroundReVisibleConveter}, ConverterParameter={StaticResource bindingProxy}}">
<Run Text="{Binding Percent, StringFormat={}{0:f1}, Converter={StaticResource exceptionValueConveter}}" />
<Run Text="%"/>
</TextBlock>
</Grid>
using System.Windows;
internal class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
/// <summary>
/// 原始数据
/// </summary>
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata(null));
/// <summary>
/// 替代数据
/// </summary>
public object Reserve
{
get { return (object)GetValue(ReserveProperty); }
set { SetValue(ReserveProperty, value); }
}
public static readonly DependencyProperty ReserveProperty = DependencyProperty.Register("Reserve", typeof(object), typeof(BindingProxy), new PropertyMetadata(null));
/// <summary>
/// 阈值
/// </summary>
public double Thread
{
get { return (double)GetValue(ThreadProperty); }
set { SetValue(ThreadProperty, value); }
}
public static readonly DependencyProperty ThreadProperty = DependencyProperty.Register("Thread", typeof(double), typeof(BindingProxy), new PropertyMetadata(0.0));
}
可直接调用资源词典
Converter.xaml
{Binding Converter={StaticResource Boolean2VisibilityConverter}}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="clr-namespace:XXX.Converters">
<BooleanToVisibilityConverter x:Key="Boolean2VisibilityConverter"/>
......
</ResourceDictionary>
DataGrid中,编辑状态下触发事件
<DataGridTextColumn Width="auto" IsReadOnly="False" MinWidth="110" Binding="{Binding Name}" Header="名称">
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<EventSetter Event="TextChanged" Handler="DataGridTextColumn_Name_TextChanged"/>
<EventSetter Event="LostFocus" Handler="DataGridTextColumn_Name_LostFocus"/>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
RadioButton绑定属性
<UserControl.Resources>
<cvt:RadioCheckConv x:Key="radioCheckConverter"/>
</UserControl.Resources>
<RadioButton Content="XXX" HorizontalAlignment="Center" GroupName="GroupName1"
IsChecked="{Binding PropertyName1, Converter={StaticResource radioCheckConverter}, ConverterParameter=1}"/>
其中,属性PropertyName1是可通知的bool;
using System;
using System.Windows.Data;
public class RadioCheckConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
{
return false;
}
if (value.ToString().Equals(parameter.ToString()))
{
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
{
return null;
}
if ((bool)value)
{
return parameter.ToString();
}
return null;
}
}
其中,当PropertyName1是DataGrid_SelectedItem的熟悉,且需要绑定成对显示,比如(是、否),可以采用
<RadioButton Content="是" GroupName="PropertyName1"
Style="{DynamicResource RadioButtonBaseStyle}" Foreground="{DynamicResource FontDefaultBrush}" FontSize="{DynamicResource FontSizeDefault}"
IsChecked="{Binding PropertyName1, Converter={StaticResource intToBoolConverter}, ConverterParameter=1}"/>
<RadioButton Content="否" GroupName="PropertyName1"
Style="{DynamicResource RadioButtonBaseStyle}" Foreground="{DynamicResource FontDefaultBrush}" FontSize="{DynamicResource FontSizeDefault}"
IsChecked="{Binding PropertyName1, Mode=OneWay, Converter={StaticResource intToBooleanReConverter}, ConverterParameter=0}"/>
绑定源的更新时机 UpdateSourceTrigger
<TextBox x:name="txt" Text="{Binding PropertName, Mode=TwoWay, UpdateSourceTrigger=Default}" />
控件绑定属性时,UpdateSourceTrigger默认为Default。源PropertName不会随着Text属性的改变而立即更新;TextBox中的变化并不是立即传递到源,而是在TextBox失去焦点后,源才更新。
UpdateSourceTrigger枚举 | 说明 | 备注 |
---|---|---|
Default | 默认值 | 默认为LostFocuse |
Explicit | 当应用程序调用 UpdateSource 方法时生效 | 通过代码手动推送来更新 |
LostFocus | 失去焦点的时候触发 | |
PropertyChanged | 属性改变的时候触发 | 源会立即更新 |
using System.Windows.Data;
private void btnUpdateSource_Click(object sender, RoutedEventArgs e)
{
// Explicit时,手动更新绑定的属性
BindingExpression binding = txt.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
}
绑定目标的绑定模式 Mode
点击按钮“更新属性值”,DemoValue会随机变化,并同步显示在Value中。
点击按钮“当前属性值”,可以根据当前的属性值(DemoValue),更新Value的显示。
1. <ProgressBar Value="{Binding DemoValue, Mode=OneTime}" />
2. <Slider Value="{Binding ElementName=TextBoxValue, Path=Text, Mode=OneWay}"/>
3. <TextBox x:Name="TextBoxValue" Text="{Binding DemoValue, Mode=OneWayToSource}" />
<TextBlock Text="{Binding DemoValue, Mode=TwoWay}" Foreground="Green"/>
Mode | 效果 | 备注 | 备注2 |
---|---|---|---|
TwoWay | 双向,绑定源变化就更新目标,绑定目标变化就更新源 | 适用于可编辑窗体或其他完全交互式方案 | 如图,若更新属性值,DemoValue会不断变化,Value实时显示,当前值为95。 |
OneWay | 单向,绑定源变化就更新目标 | 如果不需要监视目标属性的更改,此模式可避免 TwoWay 绑定模式的系统开销 | 如图,TextBox控件设置为60,Slider目标值会更新为60;若拖动Slider,TextBox不会变化,DemoValue也不变 |
OneWayToSource | 单向,绑定目标变化就更新源 | 与OneWay相反 | 如图,若TextBox控件设置为70,DemoValue会更新为70;DemoValue变化不会影响到控件的显示 |
OneTime | 当应用程序启动或DataContext更改时,更新绑定目标 | 只绑定一次,此模式在不更改源值的情况下可提供更好的性能 | 进度条的值一直是初始值(当前是50),不会变化 |
Default | 默认值,可以单向或双向 | 用户可编辑控件属性(例如文本框和复选框的属性)默认为双向绑定,而多数其他属性默认为单向绑定。 确定依赖项属性绑定在默认情况下是单向还是双向的编程方法是:使用 GetMetadata 来获取属性的属性元数据,然后检查 BindsTwoWayByDefault 属性的布尔值。 |
后台绑定
<cvt:IntToBoolConv x:Key="intToBoolConverter"/>
<CheckBox Content="启用" x:Name="CheckBox1"
IsChecked="{Binding IsEnable, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource intToBoolConverter}}" />
this.DataContext = this; // Prism可省略此步;此时IsEnable可通知客户端即可,不要求是依赖属性propdp
相当于后台实现
<CheckBox Content="启用" x:Name="CheckBox1" />
using System.Windows.Data;
BindingOperations.SetBinding(CheckBox1, // 控件名称
CheckBox.IsCheckedProperty, // 控件属性
new Binding // 绑定内容
{
Path = new PropertyPath("IsEnable"), // 依赖属性 IsEnable
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Converter = new IntToBoolConv(),
Source = this, // 属性所属对象
});