DataBinding & Converter
绑定到Enum
<Window x:Class="ArticleExample.BindEnumFull"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
SizeToContent="WidthAndHeight"
Title="Enum binding">
<Window.Resources>
<ObjectDataProvider x:Key="EnumDataSource"
ObjectType="{x:Type sys:Enum}"
MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="HorizontalAlignment" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<StackPanel Width="300" Margin="10">
<TextBlock>Choose the HorizontalAlignment value of the Button:</TextBlock>
<ListBox Name="myComboBox" SelectedIndex="0"
ItemsSource="{Binding Source={StaticResource EnumDataSource}}"/>
<Button Content="I'm a button"
HorizontalAlignment="{Binding ElementName=myComboBox, Path=SelectedItem}" />
</StackPanel>
</Window>
Binding :
BindingBase => Binding and MultiBinding
常见的Binding方式:
1. ElementName绑定到UI的另外一个元素上,并指定Path
<Window>
<StackPanel>
<Slider Name="sliderFontSize"
Minimum="1" Maximum="40" Value="10"
TickFrequency="1" TickPlacement="TopLeft"/>
<TextBlock Text="SimpleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"/>
</StackPanel>
</Window>
//binding sample with code
Binding binding = new Binding();
binding.Source=sliderObj;
binding.Path= new PropertyPath("Value");
binding.Mode=BindingMode.TwoWay;
tbObj.SetBinding(TextBlock.FontSize,binding);
//查询绑定
Binding binding = BindingOperations.GetBindinig(tbObj,TextBlock.FontSize);
2. 通过Source指定绑定源
使用Source可以绑定到静态类的属性上,或者Resource中的资源
绑定到数据本身,如int或者string等基本类型时,Path可以省略,或者以 . 表示。
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFammily,Path=Source}}"/>
<!--Or -->
<Window.Resources>
<FontFamily x:Key="CustomFont">Calibri</FontFamily>
</Window.Resources>
<TextBlock Text="{Binding Source={StaticResource CustomFont,Path=Source}}" />
3. 通过RelativeSource指定绑定源
RelativeSource主要包括:
Self: 表达式绑定到同一元素的另一个属性上
FindAncestor: 表达式绑定到父元素
PreviousData: 表达式绑定到数据绑定列表中的前一个数据项
TemplateParent: 表达式绑定到应用模板的元素,只有当绑定位于控件控件模板或数据模板内部时,这种模式才能工作。
<TextBlock Text="{Binding Path=Title,
RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}} }"/>
<!-- FindAncestor模式-->
Self,FindAncestor,PreviousData,TemplatedParent
<ControlTemplate TargetType="ListBoxItem">
<RadioButton
IsChecked=”{Binding
Path=IsSelected,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}”>
<ContentPresenter></ContentPresenter>
</ControlTemplate>
<!--还可以绑定到附加属性 -->
<Condition
Binding="{Binding Path=(local:TextBoxHelper.FocusedBorderBrush)
,RelativeSource={RelativeSource Self}
, Mode=OneWay
,Converter={StaticResource IsNotNullConverter}}"
Value="True" />
4. 通过DataContext指定绑定源
此种方式无需指定Source,通过DataContext绑定,控件会沿着控件树向上依次查找本身或者父元素的DataContext。
在xaml文件中配置d:DataContext,可以在VS的设计模式,输入绑定时,提示ViewModel的信息,并且也可以F12导航到对应的代码。
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DataContext="{d:DesignInstance local:MainWindowViewModel}"
<TextBox Text="{Binding Name}"/>
当Binding中写了. 符号后,绑定的对象试剂上是DataContext指向的对象,即ViewModel
如果是在ItemsControl中使用{Binding},则指向的是该行对应的集合里的单个Model
如:
<UserControl DataContext="{Binding VM}">
<Button Command="{Binding TestCommand}" CommandParameter="{Binding .}">Test</Button>
</UserControl>
public class UserControlViewMiodel :BindableBase{
public DelegateCommand<object> TestCommand{get;private set;}
= new DelegateCommand<object>(TestCmdHandler);
private void TestCmdHandler(object obj)
{
//obj为Button对应的DataContext,如没设置,则找Button的父节点的DataContext
}
}
绑定模式(Mode):
BindingMode主要包括以下几种:
OneWay:单向绑定,当数据源变化时,更新目标属性
TwoWay:双向绑定,主要是一些表单控件,当源属性变化时,更新目标属性,并且当目标属性变化时更新数据源
OneTime:只有第一次的绑定会生效
OneWayToSource:单向绑定,与OneWay相反
Default:大多数的行为是OneWay,但TextBox.Text是双向的。
绑定更新:
PropertyChanged:当控件属性变化时,更新数据源
LostFocus:当控件属性发生变化且丢失焦点时,更新数据源
Explicit:除非调用BindingExpression.UpdateSource(),否则无法更新数据源
Default: 大多数的默认行为时PropertyChanged,但TextBox.Text的默认行为是LostFocus
绑定Model
如果是集合类型,则使用ObservableCollection<T>类型来实现集合绑定,才具有通知的功能。
如果要绑定到集合的某个项,则
<Button DataContext="{Binding CellList[0]}"/>
MultiBinding:
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MultiCombinerConverter}">
<Binding Path="."
RelativeSource="{RelativeSource AncestorType=TabItem}" />
<Binding Path="."
RelativeSource="{RelativeSource AncestorType=TabControl}" />
</MultiBinding>
</Button.CommandParameter>
<TextBlock Text="{Binding KeyValue}">
<TextBlock.Foreground>
<MultiBinding Converter="{StaticResource boolBrushValueConverter}">
<Binding Path="KeyName"/>
<Binding Path="KeyValue"/>
<Binding Path="KeyReferValue"/>
</MultiBinding>
</TextBlock.Foreground>
</TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} / {1}{5} / {2}({3}{4})">
<Binding Path="Sex" Converter="{StaticResource SexConverter}"/>
<Binding Path="PatientWeight"/>
<Binding Path="Birthdate" Converter="{StaticResource BirthDateConverter}"/>
<Binding Path="Age" />
<Binding Path="AgeType" Converter="{StaticResource AgeTypeConverter}" />
<Binding Source="{StaticResource kg}"/>
</MultiBinding>
</TextBlock.Text>
参考 WPF 编程宝典第 4 版:第 20 章
String.Format 的使用:
IvalueConverter 的使用:
1.新建类实现 IvalueConverter 接口
2.在 xaml 文件中引入 xmlns 对应的程序集和命名空间
3.在 xaml 文件的 Resource 中定义此 key
4.在 xaml 文件绑定的元素出使用此 converter
如:
namespace System.Windows.Data;
public interface IValueConverter
{
//从Data到UI
object Convert(object value, Type targetType, object parameter, CultureInfo culture);
//从UI到Data
object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
Xaml 文件中的更改:
xmlns:local="clr-namespace:NMS.MR.FieldService.UI.GradientAmplifierStatus"
<UserControl.Resources>
<local:StatusValueConverter x:Key="StatusValueConverter"/>
</UserControl.Resources>
//此处的parameter为string类型
<Rectangle Width="10" Height="10"
Fill="{Binding Path=StatusValue,
Converter={StaticResource StatusValueConverter},
ConverterParameter=1}"/>
IMultiValueConverter:
参考 WPF 编程宝典第 4 版:20.2.6
1.定义 Convert
public class BoolBrushValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length != 3) return Brushes.White;
String keyName = values[0].ToString();
String keyValue = values[1].ToString();
String referValue = values[2].ToString();
return Brushes.Red;
}
}
2.在 XAML 文件中定义 Convert 资源
<UserControl.Resources>
<diagnosis:BoolBrushValueConverter x:Key="boolBrushValueConverter"/>
</UserControl.Resources>
3.MultiBinding 的使用
<DataGrid IsReadOnly="True" ItemsSource="{Binding DspInfo_1}" Margin="10,10"
ColumnHeaderStyle="{StaticResource Header}" RowStyle="{StaticResource RowStyle}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AutoGenerateColumns="False" Style="{DynamicResource Style}">
<DataGrid.Columns>
<DataGridTextColumn Width="*" Header="Name" Binding="{Binding KeyName }" CellStyle="{StaticResource DataGridCell}" />
<DataGridTemplateColumn Width="*" Header="Value">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding KeyValue}">
<TextBlock.Foreground>
<MultiBinding Converter="{StaticResource boolBrushValueConverter}">
<Binding Path="KeyName"/>
<Binding Path="KeyValue"/>
<Binding Path="KeyReferValue"/>
</MultiBinding>
</TextBlock.Foreground>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Width="*" Header="ReferValue" Binding="{Binding KeyReferValue,Mode=TwoWay}" CellStyle="{StaticResource DataGridCell}" />
</DataGrid.Columns>
</DataGrid>
或者结合 RelativeSource
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource SnVisibConverter}">
<Binding Path="IsSelected" RelativeSource="{RelativeSource AncestorType=ListBoxItem}" />
<Binding Path="IsMouseOver" RelativeSource="{RelativeSource AncestorType=ListBoxItem}" />
</MultiBinding>
</TextBlock.Visibility>