前言
在WPF中,Binding是一种强大的机制,用于将数据源与目标对象(通常是UI控件)进行绑定。
以下是一些常用的Binding属性及其说明:
Source: 指定数据源对象,可以是一个对象实例、属性路径、静态资源或者父级元素的属性。
1  | <TextBox Text="{Binding Path=UserName, Source={StaticResource myDataSource}}" />  | 
Path: 指定数据源中的属性路径,告诉绑定系统从哪里获取数据。
1  | <TextBox Text="{Binding Path=UserName}" />  | 
Mode: 指定绑定的方向和方式,例如单向绑定、双向绑定、或单向到源的绑定。
1  | <TextBox Text="{Binding Path=UserName, Mode=TwoWay}" />  | 
Converter: 提供一个转换器,用于在绑定源和绑定目标之间进行转换。
1  | <TextBox Text="{Binding Path=OrderTotal, Converter={StaticResource priceConverter}}" />  | 
UpdateSourceTrigger: 指定何时更新数据源的值,例如在属性更改时立即更新,或在控件失去焦点时更新。
1  | <TextBox Text="{Binding Path=UserName, UpdateSourceTrigger=PropertyChanged}" />  | 
FallbackValue: 当绑定的值无法获取时,提供一个备用的默认值。
1  | <TextBox Text="{Binding Path=OrderTotal, FallbackValue=0}" />  | 
TargetNullValue: 当目标绑定值为null时显示的值。
1  | <TextBox Text="{Binding Path=OrderTotal, TargetNullValue=Not available}" />  | 
NotifyOnSourceUpdated 和 NotifyOnTargetUpdated: 用于指定在绑定源或绑定目标更新时是否发出通知。
1  | <TextBox Text="{Binding Path=UserName, NotifyOnTargetUpdated=True}" />  | 
IsAsync: 指定是否异步处理绑定,适用于长时间运行的操作。
1  | <TextBox Text="{Binding Path=UserName, IsAsync=True}" />  | 
ValidatesOnDataErrors, ValidatesOnExceptions 和 NotifyOnValidationError: 用于指定在数据验证失败时是否发出通知,并且如何处理数据验证和异常。
1  | <TextBox Text="{Binding Path=UserName, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />  | 
这些属性可以按照需要组合使用,以便精确地控制WPF中的数据绑定行为。
作用域
当你在XAML中使用Binding时,你可以指定目标属性的作用域,通常有以下几种情况:
默认作用域:
如果你没有显式指定作用域,Binding 将在当前 DataContext 的上下文中进行搜索。
这意味着它会尝试在父元素的 DataContext 中查找绑定的属性。
ElementName 绑定:
通过设置 Binding 的 ElementName 属性,你可以指定一个具体的元素来作为绑定的目标,Binding 将在该元素的上下文中搜索属性。
RelativeSource 绑定:
通过设置 Binding 的 RelativeSource 属性,你可以指定绑定相对于其他元素的位置,比如指定为父元素或者某个特定类型的元素。
Source 绑定:
通过设置 Binding 的 Source 属性,你可以直接指定一个数据源对象,Binding 将在该对象的上下文中搜索属性。
默认作用域
如果你没有显式指定作用域,Binding 将在当前 DataContext 的上下文中进行搜索。
这意味着它会尝试在父元素的 DataContext 中查找绑定的属性。
1  | <TextBlock  | 
ElementName 绑定
简单示例
1  | <Rectangle Fill="Red" Name="rectangle"  | 
或者
1  | <StackPanel>  | 
自定义组件
自定义组件没有显式指定作用域时,默认作用域不是DataContext。
1  | <DataTemplate x:Key="BlackbordTpl" DataType="page:SubmitUserItem">  | 
RelativeSource 绑定
绑定自身属性
正方形
1  | <Rectangle Fill="Red" Height="100"  | 
绑定祖先元素属性
没有直接绑定父组件的,绑定父组件使用这种方法实现。
如果想让图片上下填充满,左右等比自适应,可以使用下面的方式实现:
1  | <Border BorderBrush="#434343" BorderThickness="1">  | 
这里
设置图片的高度后缩放方式设置为
Uniform,这样图片高度就固定了,宽度会等比缩放,再设置水平居中,就实现了这个效果。
其中
RelativeSource={RelativeSource AncestorType={x:Type Grid}}是用来指定查找祖先中最近类型为Grid的元素。
TemplatedParent
此模式允许将给定的 ControlTemplate 属性绑定到应用 ControlTemplate 的控件的属性。
为了更好地理解这里的问题,下面是一个示例
1  | <Window.Resources>  | 
如果我想应用给定控件的属性到它的控件模板,那么我可以使用TemplatedParent模式。
TemplateBinding一般用于绑定控件模板内的属性,而TemplatedParent用于在控件模板内访问父元素的属性。
TemplateBinding
在 WPF 中, TemplateBinding 用于在控件模板中绑定到控件的属性。这可以让模板基于控件的属性值更改其视觉体验。
这里是一个简单示例:MainWindow.xaml
1  | <Window x:Class="TemplateBindingDemo.MainWindow"  | 
MyButton.xaml
1  | <ResourceDictionary  | 
MyButton.cs
1  | public class MyButton : Button  | 
在这里,我们为 MyButton 定义了一个 ControlTemplate。
在模板中,我们使用 {TemplateBinding Background} 和 {TemplateBinding Content} 来绑定到控件的 Background 和 Content 属性。
所以模板会随着控件属性的改变而改变。
运行这个示例,你会看到一个蓝色的按钮,上面写着 “Button”。如果你改变 MyButton 的 Background 或 Content 属性,模板会相应更新。
Source 绑定
1  | <!-- MainWindow.xaml -->  | 
定义的ViewModel
1  | // MyViewModel.cs  | 
可绑定的值
可用来绑定的两种类型
- 使用依赖属性
 - 实现INotifyPropertyChanged接口
 
依赖属性
示例1
1  | public partial class UcBlackbord  | 
使用
1  | Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:UcBlackbord}}, Path=ShowToolbar, Converter={StaticResource BooleanToVisibilityConverter}}"  | 
示例2
1  | public partial class UcTimeNum : UserControl  | 
页面
1  | <TextBlock  | 
实现INotifyPropertyChanged接口
1  | public class MyViewModel : INotifyPropertyChanged  | 
绑定属性的查找机制
数据上下文(DataContext):如果在自定义控件内部使用数据绑定,默认情况下,绑定会从控件的
DataContext开始查找。如果控件的
DataContext设置了某个对象,那么绑定就会尝试在这个对象上查找绑定的属性。绑定路径(Binding Path):绑定路径决定了属性查找的方式。
比如,如果你在自定义控件中这样设置绑定:
1
<TextBlock Text="{Binding MyProperty}" />
这里的
MyProperty会在控件的DataContext中查找。RelativeSource:有时候,绑定可能需要在控件的容器或其它上下文中查找属性。
可以通过
RelativeSource来实现这一点。例如:
1
<TextBlock Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType=Page}}" />
这个绑定会在当前页面的
DataContext中查找MyProperty。
控件绑定属性从内部查找的原因
默认的 DataContext:
如果自定义控件的 DataContext 已经被设置为某个对象,并且控件内部的绑定没有指定路径的源,那么绑定会在控件的 DataContext 中查找。
属性的优先级:
控件的 DataContext 优先于控件容器的 DataContext,除非你明确指定了绑定的来源。
解决方案
明确指定绑定源:如果希望绑定从控件的容器中查找属性,可以使用 RelativeSource 或 ElementName 来明确指定绑定的源。
例如:
1  | <TextBlock Text="{Binding ElementName=MyPage, Path=DataContext.MyProperty}" />  | 
数据绑定注意点
- 在给组件赋值的时候我们只能在UI线程中处理,同样也只能在UI线程中对
DataContext已绑定的对象进行操作。 - 文本组件可以绑定int和double类型,不用必须为string类型。
 
另外提一下
我们在做JSON转换的时候,数字类型的值可能为空的时候,直接转对象必须属性为可空类型。
有时候为了方便处理,我们可以把属性定义为string,这样也是能成功转换的。
设置上下文
组件中
在WPF中,通过d:DataContext属性可以为设计时数据绑定设置数据上下文,这在开发和设计阶段非常有用,可以代码提醒和点击跳转到对应属性中。
指定数据上下文类:
如果你有一个名为 YourViewModel 的类作为数据上下文,可以在 d:DataContext 中引用它,以便在设计时绑定界面元素的数据。
示例:
1  | <Window ...  | 
注意事项:
- 命名空间:确保在使用
d:DataContext时正确引用你的ViewModel类的命名空间。 - 仅限设计时:
d:DataContext仅用于设计时数据绑定,不影响运行时的实际数据绑定和行为。 - 设计时数据源:这允许在没有运行时数据源的情况下预览和调试界面。
 
DataTemplate中
在DataTemplate中使用DataType指定
1  | <DataTemplate x:Key="TjItemDt"  | 
数据绑定
定义基类
1  | using System.ComponentModel;  | 
定义数据源的类
1  | public class ToolbarModel : ZNotifyModel  | 
上面例子中我们可以看到,
如果我们要在数据改变时通知页面改变的属性都要在Set方法中调用OnPropertyChanged
而列表不再用List,而是使用ObservableCollection
ObservableCollection
注意ObservableCollection中调用Add方法会触发列表刷新,但是如果直接更换了对象就不会刷新了。
方式1
如下示例
1  | int pageSize = 15;  | 
其中pageList必须调用OnPropertyChanged方法才会刷新
1  | public class JianDaDetailPageData : ZNotifyModel  | 
方式2
如果pageList保持原样那么赋值只能使用Add方法
1  | this._pageData.pageList.Clear();  | 
对应
1  | public class JianDaDetailPageData : ZNotifyModel  | 
设置数据源
代码中也要进行数据源的设置
1  | pageData.IsRight = true;  | 
上面设置整个页面的数据,当然也可以设置某个组件的数据源
1  | this.toolbar_list.DataContext = mydata;  | 
页面中绑定值
1  | <Window.Resources>  | 
双向绑定
1  | <TextBox Grid.Row="0" Text="{Binding Title,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"/>  | 
关键属性 UpdateSourceTrigger=PropertyChanged,Mode=TwoWay
转换器
https://www.psvmc.cn/article/2019-12-30-wpf-start-03-converter.html
自定义代码片段
上面属性写的时候比较麻烦,建议使用自定义代码片段。
Visual Studio创建
在任意地方创建一个文件夹,最好是你不去经常移动的地方,文件夹是用来存放你自定义的代码块的文件夹,
我就创建了一个名称:csharp_snippet 的文件夹
新建代码块文件zprop.snippet
1  | 
  | 
保存啦,然后依然是去 工具–>代码段管理器 –>选择Visual C#语言 –>选择下方的添加 –>浏览到你自定义的那个放代码块的文件夹就OK啦。
重启开发工具。
此时要我在项目中打出zprop按两次Tab 那我的数据访问层的代码就全部出来啦,当然还要添加一些引用就可以啦
ReSharper插件创建
安装ReSharper插件后,所有自定义的代码段都失效了,是因为
安装ReSharper插件后,它会自动导入代码段,但是后来的代码段是不会被导入的,只能我们自己添加。
配置步骤查看:
https://www.psvmc.cn/article/2019-12-27-resharper-config.html