数据绑定定义数据绑定是在应用 UI 与其显示的数据之间建立连接的过程。DataContext数据上下文定义一个属性继承自FrameworkElement因此所有控件都有类型为object一般放viewmodel对象。性质DataContext具有​​继承性​​子控件会自动继承父容器的DataContext。DataContext​​是WPF中​​数据绑定的默认源​​例Grid !-- 继承Window的DataContext -- StackPanel !-- 继承Grid的DataContext -- Slider Value{Binding SliderValue}/ !-- 仍然绑定到DataModel -- /StackPanel /GridViewmodel属性要在View中显示要将ViewModel对象赋值给View的DataContext数据上下文属性Binding绑定查看Binding的定义中构造函数WPF中一切都是类而Binding也是一个类public Binding(); public Binding(string path);Binding的4种数据源总结4种方式的path都是属性绑定就是目标属性和被赋值的属性关联只是数据源不同和写法不同1DataContext隐式源源当前元素沿逻辑树继承下来的DataContext。场景MVVM 的主方式。整个页面/整块区域共享一个 ViewModel所有绑定都只写Path。Text{Binding Person.Name}上面代码实例化了一个Binding对象Person.Name赋值给Path等于当前的DataContext默认数据源中那个ViewModel对象的Person.Name属性2Source显式对象是Binding对象的一个object类型属性源你明确指定的某个对象比如资源、单例、静态对象、x:Static。场景这个值不在 DataContext 里或者你想让绑定不受 DataContext 影响。绑定到画刷资源的Color绑定到全局配置单例绑定到静态字段/系统参数。Text{Binding Source{StaticResource RedBrush},PathColor}3ElementName另一个控件是Binding对象的一个string类型属性源同一个 XAML 里另一个有x:Name的控件。场景纯 UI 联动不需要 ViewModel 参与。一个 TextBlock 显示 Slider 的当前值一个预览区显示 TextBox 的输入一个按钮的IsEnabled绑到某个 CheckBox一个进度条绑到 Slider。Text{Binding ElementNamepanel, PathMargin}4 RelativeSource相对源Mode源是谁典型场景Self绑定目标自己控件自己的两个属性联动比如 ToolTip 显示自己的值、TextBlock 的 Text 绑自己的 TagFindAncestor父链上某个类型的控件子控件拿父容器/父控件的数据DataGrid 单元格里的按钮找 DataGrid/WindowTemplatedParent应用模板的那个控件ControlTemplate 内部模板子元素绑控件的属性PreviousData数据项列表里的上一项ItemsControl 的项模板里当前项和上一项比较自己的前景色显示到Text属性上Text{Binding RelativeSource{RelativeSource ModeSelf},PathForeground}从当前控件开始找上级一个类型为StackPanel的控件并把这个StackPanel控件的Margin显示到当前控件的Text属性上Text{Binding RelativeSource{RelativeSource ModeFindAncestor,AncestorTypeStackPanel},PathMargin}AncestorLevel获取或设置要查找的上级级别。 使用 1 指示最靠近绑定目标元素的项。绑定的四种模式mode属性相对源的mode是RelativeSource自己的属性不冲突。枚举值说明TwoWay双向绑定即导致更改源属性或目标属性时自动更新另一方。OneWay单向绑定在更改绑定源源时更新绑定目标目标。OneTime一次绑定在应用程序启动或数据上下文更改时更新绑定目标。OneWayToSource在目标属性更改时更新源属性。Default默认绑定文本框的默认绑定是双向的而其他大多数属性默认为单向绑定。改变时机什么是改变时机其实就是如果前端的值发生改变后端的值在什么时候跟着改变。它由Binding类的UpdateSourceTrigger属性的值决定 。这个属性也是一个枚举类型枚举值说明Default采用控件各自的UpdateSourceTrigger默认值。PropertyChanged每当绑定目标属性发生更改时都会更新绑定源。LostFocus每当绑定目标元素失去焦点时都会更新绑定源。Explicit仅在调用 System.Windows.Data.BindingExpression.UpdateSource 方法时更新绑定源。双向绑定属性通知引入前端属性值发生改变后由UpdateSourceTrigger决定什么时候更新后端的Model属性值但是后端那些Model的属性值发生改变后前端什么时候跟着改变需不需要做特殊的处理答案是需要如果Model中的那些属性没有实现属性通知就算前后端成功的建立了绑定关系后端Model属性值改变时前端的显示是没有变化的如果要实时跟着变化则需要掌握WPF的INotifyPropertyChanged接口以及属性通知的相关知识点。当不实现通知时只是前端改变使得后端改变属性通知自己实现通知要实现属性通知要继承INotifyPropertyChanged接口public interface INotifyPropertyChanged { event PropertyChangedEventHandler PropertyChanged; }定义一个特别的类来实现这个功能要通知的话要继承这个类委托一组方法的引用列表事件委托的包装器使得这个类以外的类只能对委托进行订阅-退订操作public class ObservableObject : INotifyPropertyChanged { //定义一个事件 public event PropertyChangedEventHandler PropertyChanged; //[CallerMemberName]属性中使用这个方法自动填写属性名称给到propertyName public void RaisePropertyChanged([CallerMemberName] string propertyName ) { //委托调用同步、按订阅顺序依次调用这个委托中装的方法 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }使用CommunityToolkit.Mvvm工具包实现ObservableCollection泛型集合转换器IValueConverter转换器定义Binding类的属性是一个IValueConverter接口前后端建立绑定时定义一套自定义逻辑让前端显示的数据与后端获取的数据建立一定的对应关系。下方代码为一个bool类型属性对应textblock是否可见的实例定义转换规则类//必须继承IValueConverter接口 public class BooltoVisiableConverst : IValueConverter { //源到页面 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value is true? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value is Visibility.Visible; } }资源中实例化转换规则类local:BooltoVisiableConverst x:KeyBooltoVisiableConverst/local:BooltoVisiableConverst属性绑定函数计算结果TextBox Visibility{Binding Isbusy,Converter{StaticResource BooltoVisiableConverst}}/TextBoxIMultiValueConverter多值转换器使用场景当你要给某个控件属性赋值时它的值取决于“多个来源”而且其中至少一个来源 ViewModel 拿不到来源例子ViewModel 能拿到吗① ViewModel 里的数据Ratio、Price、IsEdit✔ 拿得到② 控件自己的尺寸/位置ActualWidth、ActualHeight、ActualTop、RenderSize✘ 拿不到③ 其它控件的状态另一个控件的IsSelected、Value、Text、IsChecked✘ 拿不到示例一个占父控件百分之65宽带的色块定义转换规则类//多值转换 public class RatioToWidth : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { double hostWidth (double)values[0]; // 容器宽度 double ratio (double)values[1]; // 比例 0~1 return hostWidth * ratio; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }资源中实例化local:RatioToWidth x:KeyRatioToWidth/local:RatioToWidth控件使用Grid x:NameBarHost Height40 Margin20 Background#EEEEEE Rectangle FillDodgerBlue HorizontalAlignmentLeft Rectangle.Width MultiBinding Converter{StaticResource RatioToWidth} Binding PathActualWidth ElementNameBarHost/ Binding PathRatio/ /MultiBinding /Rectangle.Width /Rectangle /GridValidationRule验证规则在“界面输入 → ViewModel”这一步拦截非法值。原始效果当规则验证为不通过时框会变红定义验证类必须继承抽象类ValidationRule必须重写Validate方法返回类型ValidationResult构造函数如下public ValidationResult(bool isValid, object errorContent) { _isValid isValid; _errorContent errorContent; }internal class AgeRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { if(value null) { return new ValidationResult(false,为空); } else if (int.Parse((string)value) 150|| int.Parse((string)value) 0) { return new ValidationResult(false, 我一眼就看出你不是人); } else { return new ValidationResult(true, 对的对的); } } }控件绑定中指定验证规则绑定Binding有一个ValidationRule类型的集合属性可以放多条规则TextBox Margin10 TextBox.Text Binding PathText UpdateSourceTriggerLostFocus Binding.ValidationRules ValidationSpace:AgeRule / /Binding.ValidationRules /Binding /TextBox.Text /TextBox修改当验证为失败时的样式(Validation.Errors)[0].ErrorContentValidation.Errors是附加属性是一个数组(Validation.Errors)是附加属性的写法ErrorContent是继承了ValidationRule的类的返回值类型构造函数的第二次参数Validation.HasError true有错误的时候被置为true绑定表达式内部链路1. 用户输入 → TextBox.Text 变化2. Binding 执行转换3. 依次调用 ValidationRules 里的每个 Validate4. 结果├─ 全部通过 → 写入源属性清空 Errors└─ 某条失败 → 往 TextBox 上写Validation.Errors附加属性并设置Validation.HasError true源属性不更新代码实现TextBox x:Nameaaa Margin10 TextBox.Text Binding PathText UpdateSourceTriggerLostFocus Binding.ValidationRules ValidationSpace:AgeRule / /Binding.ValidationRules /Binding /TextBox.Text TextBox.Style Style TargetTypeTextBox Style.Triggers Trigger PropertyValidation.HasError ValueTrue Setter PropertyBorderBrush ValueRed / Setter PropertyBorderThickness Value2 / Setter PropertyBackground Value#FFF0F0 / /Trigger /Style.Triggers /Style /TextBox.Style /TextBox TextBlock TextBlock.Text Binding ElementNameaaa ModeOneWay Path(Validation.Errors)[0].ErrorContent / /TextBlock.Text /TextBlock