C# .Net 4.0中.Net 4.5绑定的延迟属性
如何在.Net 4.0中的绑定上实现.Net 4.5(已描述)中的延迟属性 我知道我不能从BindingBase继承,因为ProvideValue是密封的C# .Net 4.0中.Net 4.5绑定的延迟属性,c#,wpf,binding,.net-4.0,.net-4.5,C#,Wpf,Binding,.net 4.0,.net 4.5,如何在.Net 4.0中的绑定上实现.Net 4.5(已描述)中的延迟属性 我知道我不能从BindingBase继承,因为ProvideValue是密封的 我可以实现MarkupExtension,但这意味着我现在必须从BindingExtension重写所有属性。还有其他方法吗?我将创建一个指定延迟时间的AttachedProperty。AttachedProperty将在绑定值更改时启动(或重置)计时器,并在达到指定的时间量时手动更新绑定源 您可以使用以下命令更新源绑定: BindingOp
我可以实现MarkupExtension,但这意味着我现在必须从BindingExtension重写所有属性。还有其他方法吗?我将创建一个指定延迟时间的
AttachedProperty
。AttachedProperty
将在绑定值更改时启动(或重置)计时器,并在达到指定的时间量时手动更新绑定源
您可以使用以下命令更新源绑定:
BindingOperations.GetBindingExpressionBase(
dependencyObject, dependencyProperty).UpdateSource();
编辑
我今天正在修复一些旧代码中的一个bug,注意到它使用附加的行为实现了延迟的属性更改通知。我想到了这个问题,所以按照我在代码中注释过的链接,发现自己遇到了一个问题,我不久前在Soabout上发布了这个问题。最重要的答案是我目前实现的一个,它是一些附加属性,在X毫秒过去后更新绑定的源。直接移植是不可能的,但是我们可以使用
多绑定来“模拟”它吗
请注意,这是一个非常紧密耦合的解决方案,如果在一个页面上使用了许多这样的绑定,那么可能无法很好地执行
两个必须有一个
它接受单个项目ArrayList
中以毫秒为单位的延迟作为转换器参数李>
每个这样的延迟绑定都必须携带自己的转换器参数实例
测试XAML如下所示
<TextBlock xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:System="clr-namespace:System;assembly=mscorlib" >
<TextBlock.Resources>
<local:DelayHelper x:Key="DelayHelper"/>
<Collections:ArrayList x:Key="MultiConverterParameter">
<System:Int32>2000</System:Int32>
</Collections:ArrayList>
</TextBlock.Resources>
<TextBlock.Text>
<MultiBinding UpdateSourceTrigger="LostFocus"
Converter="{StaticResource DelayHelper}"
ConverterParameter="{StaticResource MultiConverterParameter}">
<Binding Path="Text" ElementName="MyTextBox" Mode="OneWay" />
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding BindsDirectlyToSource="True"
Source="{x:Static TextBlock.TextProperty}"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBox x:Name="MyTextBox" Text="Test..."/>
所以这段代码利用了
多重绑定可以接受目标UI元素(TextBlock
)及其本身是多重绑定的依赖属性(TextBlock.TextProperty
)
绑定后,多重绑定无法更改其属性,包括converterParameter
。但是转换器参数本身可以是一个引用对象,在整个绑定过程中保持其引用处于活动状态,例如ArrayList
调度程序在第一次勾选后必须停止。因此,我们使用temp
变量是非常必要的
更新为每个源文本更新进行2次转换器传递。这种行为没有escpae。如果使用了许多延迟绑定,这可能会导致速度缓慢
确保在多个延迟绑定之间不共享相同的转换器参数
让我知道这是否有帮助…最后,我决定使用composition实现DelayedBinding作为MarkupExtension
我遇到的唯一问题是,如果IProvideValueTarget
中的TargetProperty
为空,则DataTemplatesProvideValue
应返回此值
[MarkupExtensionReturnType(typeof(object))]
public class DelayedBindingExtension : MarkupExtension
{
private readonly Binding _binding = new Binding();
public DelayedBindingExtension()
{
//Default value for delay
Delay = TimeSpan.FromSeconds(0.5);
}
public DelayedBindingExtension(PropertyPath path)
: this()
{
Path = path;
}
#region properties
[DefaultValue(null)]
public object AsyncState
{
get { return _binding.AsyncState; }
set { _binding.AsyncState = value; }
}
[DefaultValue(false)]
public bool BindsDirectlyToSource
{
get { return _binding.BindsDirectlyToSource; }
set { _binding.BindsDirectlyToSource = value; }
}
[DefaultValue(null)]
public IValueConverter Converter
{
get { return _binding.Converter; }
set { _binding.Converter = value; }
}
[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter)), DefaultValue(null)]
public CultureInfo ConverterCulture
{
get { return _binding.ConverterCulture; }
set { _binding.ConverterCulture = value; }
}
[DefaultValue(null)]
public object ConverterParameter
{
get { return _binding.ConverterParameter; }
set { _binding.ConverterParameter = value; }
}
[DefaultValue(null)]
public string ElementName
{
get { return _binding.ElementName; }
set { _binding.ElementName = value; }
}
[DefaultValue(null)]
public object FallbackValue
{
get { return _binding.FallbackValue; }
set { _binding.FallbackValue = value; }
}
[DefaultValue(false)]
public bool IsAsync
{
get { return _binding.IsAsync; }
set { _binding.IsAsync = value; }
}
[DefaultValue(BindingMode.Default)]
public BindingMode Mode
{
get { return _binding.Mode; }
set { _binding.Mode = value; }
}
[DefaultValue(false)]
public bool NotifyOnSourceUpdated
{
get { return _binding.NotifyOnSourceUpdated; }
set { _binding.NotifyOnSourceUpdated = value; }
}
[DefaultValue(false)]
public bool NotifyOnTargetUpdated
{
get { return _binding.NotifyOnTargetUpdated; }
set { _binding.NotifyOnTargetUpdated = value; }
}
[DefaultValue(false)]
public bool NotifyOnValidationError
{
get { return _binding.NotifyOnValidationError; }
set { _binding.NotifyOnValidationError = value; }
}
[DefaultValue(null)]
public PropertyPath Path
{
get { return _binding.Path; }
set { _binding.Path = value; }
}
[DefaultValue(null)]
public RelativeSource RelativeSource
{
get { return _binding.RelativeSource; }
set { _binding.RelativeSource = value; }
}
[DefaultValue(null)]
public object Source
{
get { return _binding.Source; }
set { _binding.Source = value; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter
{
get { return _binding.UpdateSourceExceptionFilter; }
set { _binding.UpdateSourceExceptionFilter = value; }
}
[DefaultValue(UpdateSourceTrigger.Default)]
public UpdateSourceTrigger UpdateSourceTrigger
{
get { return _binding.UpdateSourceTrigger; }
set { _binding.UpdateSourceTrigger = value; }
}
[DefaultValue(null)]
public object TargetNullValue
{
get { return _binding.TargetNullValue; }
set { _binding.TargetNullValue = value; }
}
[DefaultValue(null)]
public string StringFormat
{
get { return _binding.StringFormat; }
set { _binding.StringFormat = value; }
}
[DefaultValue(false)]
public bool ValidatesOnDataErrors
{
get { return _binding.ValidatesOnDataErrors; }
set { _binding.ValidatesOnDataErrors = value; }
}
[DefaultValue(false)]
public bool ValidatesOnExceptions
{
get { return _binding.ValidatesOnExceptions; }
set { _binding.ValidatesOnExceptions = value; }
}
[DefaultValue(null)]
public string XPath
{
get { return _binding.XPath; }
set { _binding.XPath = value; }
}
[DefaultValue(null)]
public Collection<ValidationRule> ValidationRules
{
get { return _binding.ValidationRules; }
}
#endregion
[DefaultValue(null)]
public TimeSpan Delay { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
try
{
_binding.Mode = BindingMode.TwoWay;
_binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
}
catch (InvalidOperationException) //Binding in use already don't change it
{
}
var valueProvider = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideValueTarget;
if (valueProvider != null)
{
var bindingTarget = valueProvider.TargetObject as DependencyObject;
var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
if (bindingProperty != null && bindingTarget != null)
{
var result = (BindingExpression)_binding.ProvideValue(serviceProvider);
new DelayBindingManager(result, bindingTarget, bindingProperty, Delay);
return result;
}
}
return this;
}
private class DelayBindingManager
{
private readonly BindingExpressionBase _bindingExpression;
private readonly DependencyProperty _bindingTargetProperty;
private DependencyPropertyDescriptor _descriptor;
private readonly DispatcherTimer _timer;
public DelayBindingManager(BindingExpressionBase bindingExpression, DependencyObject bindingTarget, DependencyProperty bindingTargetProperty, TimeSpan delay)
{
_bindingExpression = bindingExpression;
_bindingTargetProperty = bindingTargetProperty;
_descriptor = DependencyPropertyDescriptor.FromProperty(_bindingTargetProperty, bindingTarget.GetType());
if (_descriptor != null)
_descriptor.AddValueChanged(bindingTarget, BindingTargetTargetPropertyChanged);
_timer = new DispatcherTimer();
_timer.Tick += TimerTick;
_timer.Interval = delay;
}
private void BindingTargetTargetPropertyChanged(object sender, EventArgs e)
{
var source = (DependencyObject)sender;
if (!BindingOperations.IsDataBound(source, _bindingTargetProperty))
{
if (_descriptor != null)
{
_descriptor.RemoveValueChanged(source, BindingTargetTargetPropertyChanged);
_descriptor = null;
}
return;
}
_timer.Stop();
_timer.Start();
}
private void TimerTick(object sender, EventArgs e)
{
_timer.Stop();
_bindingExpression.UpdateSource();
}
}
}
[MarkupExtensionReturnType(typeof(object))]
公共类DelayedBindingExtension:MarkupExtension
{
私有只读绑定_Binding=新绑定();
公共DelayedBindingExtension()
{
//延迟的默认值
延迟=从秒开始的时间跨度(0.5);
}
公共DelayedBindingExtension(PropertyPath路径)
:此()
{
路径=路径;
}
#区域属性
[默认值(空)]
公共对象异步状态
{
获取{return\u binding.AsyncState;}
设置{u binding.AsyncState=value;}
}
[默认值(false)]
公共bool BindsDirectlyToSource
{
获取{return\u binding.BindsDirectlyToSource;}
设置{u binding.BindsDirectlyToSource=value;}
}
[默认值(空)]
公用变频器
{
获取{return\u binding.Converter;}
设置{u binding.Converter=value;}
}
[TypeConverter(typeof(CultureInfoietFlangGetAgConverter)),默认值(null)]
公共文化信息转换器文化
{
获取{return\u binding.ConverterCulture;}
设置{u binding.ConverterCulture=value;}
}
[默认值(空)]
公共对象转换器参数
{
获取{return\u binding.ConverterParameter;}
设置{u binding.ConverterParameter=value;}
}
[默认值(空)]
公共字符串元素名
{
获取{return\u binding.ElementName;}
设置{u binding.ElementName=value;}
}
[默认值(空)]
公共对象回退值
{
获取{return\u binding.FallbackValue;}
设置{u binding.FallbackValue=value;}
}
[默认值(false)]
公共广播同步
{
获取{return\u binding.IsAsync;}
设置{u binding.IsAsync=value;}
}
[默认值(BindingMode.Default)]
公共绑定模式
{
获取{return\u binding.Mode;}
设置{u binding.Mode=value;}
}
[默认值(false)]
公共bool NotifyOnSourceUpdated
{
获取{return\u binding.NotifyOnSourceUpdated;}
设置{u binding.NotifyOnSourceUpdated=value;}
}
[默认值(false)]
公共布尔NotifyOnTargetUpdated
{
获取{return\u binding.NotifyOnTargetUpdated;}
设置{u binding.NotifyOnTargetUpdated=value;}
}
[默认值(false)]
公共布尔NotifyOnValidationError
{
获取{return\u binding.NotifyOnValidationError;}
设置{u binding.NotifyOnValidationError=value;}
}
[默认值(空)]
公共属性路径
{
获取{return\u binding.Path;}
设置{u binding.Path=value;}
}
[默认值(空)]
公共相对资源相对资源
{
获取{return\u binding.RelativeSource;}
设置{u binding.RelativeSource=value;}
}
[默认值(空)]
公共对象源
{
获取{return\u binding.Source;}
设置{u binding.Source=value;}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hi
[MarkupExtensionReturnType(typeof(object))]
public class DelayedBindingExtension : MarkupExtension
{
private readonly Binding _binding = new Binding();
public DelayedBindingExtension()
{
//Default value for delay
Delay = TimeSpan.FromSeconds(0.5);
}
public DelayedBindingExtension(PropertyPath path)
: this()
{
Path = path;
}
#region properties
[DefaultValue(null)]
public object AsyncState
{
get { return _binding.AsyncState; }
set { _binding.AsyncState = value; }
}
[DefaultValue(false)]
public bool BindsDirectlyToSource
{
get { return _binding.BindsDirectlyToSource; }
set { _binding.BindsDirectlyToSource = value; }
}
[DefaultValue(null)]
public IValueConverter Converter
{
get { return _binding.Converter; }
set { _binding.Converter = value; }
}
[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter)), DefaultValue(null)]
public CultureInfo ConverterCulture
{
get { return _binding.ConverterCulture; }
set { _binding.ConverterCulture = value; }
}
[DefaultValue(null)]
public object ConverterParameter
{
get { return _binding.ConverterParameter; }
set { _binding.ConverterParameter = value; }
}
[DefaultValue(null)]
public string ElementName
{
get { return _binding.ElementName; }
set { _binding.ElementName = value; }
}
[DefaultValue(null)]
public object FallbackValue
{
get { return _binding.FallbackValue; }
set { _binding.FallbackValue = value; }
}
[DefaultValue(false)]
public bool IsAsync
{
get { return _binding.IsAsync; }
set { _binding.IsAsync = value; }
}
[DefaultValue(BindingMode.Default)]
public BindingMode Mode
{
get { return _binding.Mode; }
set { _binding.Mode = value; }
}
[DefaultValue(false)]
public bool NotifyOnSourceUpdated
{
get { return _binding.NotifyOnSourceUpdated; }
set { _binding.NotifyOnSourceUpdated = value; }
}
[DefaultValue(false)]
public bool NotifyOnTargetUpdated
{
get { return _binding.NotifyOnTargetUpdated; }
set { _binding.NotifyOnTargetUpdated = value; }
}
[DefaultValue(false)]
public bool NotifyOnValidationError
{
get { return _binding.NotifyOnValidationError; }
set { _binding.NotifyOnValidationError = value; }
}
[DefaultValue(null)]
public PropertyPath Path
{
get { return _binding.Path; }
set { _binding.Path = value; }
}
[DefaultValue(null)]
public RelativeSource RelativeSource
{
get { return _binding.RelativeSource; }
set { _binding.RelativeSource = value; }
}
[DefaultValue(null)]
public object Source
{
get { return _binding.Source; }
set { _binding.Source = value; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter
{
get { return _binding.UpdateSourceExceptionFilter; }
set { _binding.UpdateSourceExceptionFilter = value; }
}
[DefaultValue(UpdateSourceTrigger.Default)]
public UpdateSourceTrigger UpdateSourceTrigger
{
get { return _binding.UpdateSourceTrigger; }
set { _binding.UpdateSourceTrigger = value; }
}
[DefaultValue(null)]
public object TargetNullValue
{
get { return _binding.TargetNullValue; }
set { _binding.TargetNullValue = value; }
}
[DefaultValue(null)]
public string StringFormat
{
get { return _binding.StringFormat; }
set { _binding.StringFormat = value; }
}
[DefaultValue(false)]
public bool ValidatesOnDataErrors
{
get { return _binding.ValidatesOnDataErrors; }
set { _binding.ValidatesOnDataErrors = value; }
}
[DefaultValue(false)]
public bool ValidatesOnExceptions
{
get { return _binding.ValidatesOnExceptions; }
set { _binding.ValidatesOnExceptions = value; }
}
[DefaultValue(null)]
public string XPath
{
get { return _binding.XPath; }
set { _binding.XPath = value; }
}
[DefaultValue(null)]
public Collection<ValidationRule> ValidationRules
{
get { return _binding.ValidationRules; }
}
#endregion
[DefaultValue(null)]
public TimeSpan Delay { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
try
{
_binding.Mode = BindingMode.TwoWay;
_binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
}
catch (InvalidOperationException) //Binding in use already don't change it
{
}
var valueProvider = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideValueTarget;
if (valueProvider != null)
{
var bindingTarget = valueProvider.TargetObject as DependencyObject;
var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
if (bindingProperty != null && bindingTarget != null)
{
var result = (BindingExpression)_binding.ProvideValue(serviceProvider);
new DelayBindingManager(result, bindingTarget, bindingProperty, Delay);
return result;
}
}
return this;
}
private class DelayBindingManager
{
private readonly BindingExpressionBase _bindingExpression;
private readonly DependencyProperty _bindingTargetProperty;
private DependencyPropertyDescriptor _descriptor;
private readonly DispatcherTimer _timer;
public DelayBindingManager(BindingExpressionBase bindingExpression, DependencyObject bindingTarget, DependencyProperty bindingTargetProperty, TimeSpan delay)
{
_bindingExpression = bindingExpression;
_bindingTargetProperty = bindingTargetProperty;
_descriptor = DependencyPropertyDescriptor.FromProperty(_bindingTargetProperty, bindingTarget.GetType());
if (_descriptor != null)
_descriptor.AddValueChanged(bindingTarget, BindingTargetTargetPropertyChanged);
_timer = new DispatcherTimer();
_timer.Tick += TimerTick;
_timer.Interval = delay;
}
private void BindingTargetTargetPropertyChanged(object sender, EventArgs e)
{
var source = (DependencyObject)sender;
if (!BindingOperations.IsDataBound(source, _bindingTargetProperty))
{
if (_descriptor != null)
{
_descriptor.RemoveValueChanged(source, BindingTargetTargetPropertyChanged);
_descriptor = null;
}
return;
}
_timer.Stop();
_timer.Start();
}
private void TimerTick(object sender, EventArgs e)
{
_timer.Stop();
_bindingExpression.UpdateSource();
}
}
}