非依赖属性绑定解决方案

WPF开发过程中,经常会遇到需要对非依赖属性进行双向绑定的情况。例如,Office功能区的ribbon组或转换器的参数。如果尝试进行绑定,通常会抛出异常,提示无法在非依赖属性上设置绑定。本文将介绍一种解决方案,通过创建一个代理/观察者对象来实现数据的双向同步。

XAML代码示例

以下是使用代理在XAML中的代码示例。这里没有使用代码后置(code-behind)。

<Window x:Class="BindOnNonDependencyProperty.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:us="clr-namespace:BindOnNonDependencyProperty" Title="BindOnNonDependencyProperty"> <DockPanel> <TextBox x:Name="myTextBox" DockPanel.Dock="Top" /> <TextBox x:Name="monTextBlockCible" DockPanel.Dock="Top" /> <us:ExtendedBinding Source="{Binding ElementName=myTextBox,Path=Text,Mode=TwoWay}" Target="{Binding ElementName=monTextBlockCible,Path=Text,Mode=TwoWay}" /> </DockPanel> </Window>

代理/观察者的基类

将创建一个名为ExtendedBinding的代理/观察者,它必须继承自DependencyObject才能拥有DependencyProperty。但是,将DependencyObject添加到XAML中的唯一方法是将其添加到资源字典中。这样做的缺点是,它将不再在控件树中,因此无法在其属性上进行绑定

然而,将其作为UIElement添加到控件树中是行不通的,因为在当前版本的框架中,不会有DataContext的继承,而且使用ElementName绑定将被禁止。幸运的是,有一种解决方案:代理必须继承自FrameworkElement,这样一切都会正常工作。

依赖属性

将添加两个依赖属性,一个作为目标,另一个作为源。这些依赖属性将使用FrameworkPropertyMetadata进行自定义,以启用以下功能:

  • 绑定将使用双向模式
  • 使用的UpdateSourceTrigger将是PropertyChanged事件

工作原理

最终代码

public class ExtendedBinding : FrameworkElement { #region Source DP public static readonly DependencyProperty SourceProperty = DependencyProperty.Register( "Source", typeof(object), typeof(ExtendedBinding), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, }); public Object Source { get { return GetValue(ExtendedBinding.SourceProperty); } set { SetValue(ExtendedBinding.SourceProperty, value); } } #endregion #region Target DP public static readonly DependencyProperty TargetProperty = DependencyProperty.Register( "Target", typeof(object), typeof(ExtendedBinding), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, }); public Object Target { get { return GetValue(ExtendedBinding.TargetProperty); } set { SetValue(ExtendedBinding.TargetProperty, value); } } #endregion protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.Property.Name == ExtendedBinding.SourceProperty.Name) { // no loop wanted if (!object.ReferenceEquals(Source, Target)) Target = Source; } else if (e.Property.Name == ExtendedBinding.TargetProperty.Name) { // no loop wanted if (!object.ReferenceEquals(Source, Target)) Source = Target; } } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485