准备进行代码转储。
我使用了一个WPF伪行为(一种像行为的附加DP)。这段代码可以工作,但它并不美观,可能会导致泄漏。可能需要将所有引用替换为弱引用等。
这是行为类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Data;
using System.ComponentModel;
namespace BehaviorForDelayedTrigger
{
public static class DelayedUpdateBehavior
{
#region TargetProperty Attached DependencyProperty
public static readonly DependencyProperty TargetPropertyProperty = DependencyProperty.RegisterAttached(
TargetPropertyPropertyName,
typeof(DependencyProperty),
typeof(DelayedUpdateBehavior),
new FrameworkPropertyMetadata(null, OnTargetPropertyChanged)
);
public const string TargetPropertyPropertyName = "TargetProperty";
public static void SetTargetProperty(DependencyObject element, DependencyProperty value)
{
element.SetValue(TargetPropertyProperty, value);
}
public static DependencyProperty GetTargetProperty(DependencyObject element)
{
return (DependencyProperty)element.GetValue(TargetPropertyProperty);
}
private static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var prop = e.NewValue as DependencyProperty;
if(prop == null)
return;
d.Dispatcher.BeginInvoke(
(Action<DependencyObject, DependencyProperty>)
((target, p) => new PropertyChangeTimer(target, p)),
DispatcherPriority.ApplicationIdle,
d,
prop);
}
#endregion
#region Milliseconds Attached DependencyProperty
public static readonly DependencyProperty MillisecondsProperty = DependencyProperty.RegisterAttached(
MillisecondsPropertyName,
typeof(int),
typeof(DelayedUpdateBehavior),
new FrameworkPropertyMetadata(1000)
);
public const string MillisecondsPropertyName = "Milliseconds";
public static void SetMilliseconds(DependencyObject element, int value)
{
element.SetValue(MillisecondsProperty, value);
}
public static int GetMilliseconds(DependencyObject element)
{
return (int)element.GetValue(MillisecondsProperty);
}
#endregion
private class PropertyChangeTimer
{
private DispatcherTimer _timer;
private BindingExpression _expression;
public PropertyChangeTimer(DependencyObject target, DependencyProperty property)
{
if (target == null)
throw new ArgumentNullException("target");
if (property == null)
throw new ArgumentNullException("property");
if (!BindingOperations.IsDataBound(target, property))
return;
_expression = BindingOperations.GetBindingExpression(target, property);
if (_expression == null)
throw new InvalidOperationException("No binding was found on property "+ property.Name + " on object " + target.GetType().FullName);
DependencyPropertyDescriptor.FromProperty(property, target.GetType()).AddValueChanged(target, OnPropertyChanged);
}
private void OnPropertyChanged(object sender, EventArgs e)
{
if (_timer == null)
{
_timer = new DispatcherTimer();
int ms = DelayedUpdateBehavior.GetMilliseconds(sender as DependencyObject);
_timer.Interval = TimeSpan.FromMilliseconds(ms);
_timer.Tick += OnTimerTick;
_timer.Start();
return;
}
_timer.Stop();
_timer.Start();
}
private void OnTimerTick(object sender, EventArgs e)
{
_expression.UpdateSource();
_expression.UpdateTarget();
_timer.Stop();
_timer = null;
}
}
}
}
以下是一个使用示例:
<Window
x:Class="BehaviorForDelayedTrigger.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:t="clr-namespace:BehaviorForDelayedTrigger">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition
Height="auto" />
</Grid.RowDefinitions>
<Viewbox>
<TextBlock
x:Name="TargetTextBlock"
Background="Red" />
</Viewbox>
<TextBox
t:DelayedUpdateBehavior.TargetProperty="{x:Static TextBox.TextProperty}"
t:DelayedUpdateBehavior.Milliseconds="1000"
Grid.Row="1"
Text="{Binding Text, ElementName=TargetTextBlock, UpdateSourceTrigger=Explicit}" />
</Grid>
</Window>
这段话的核心思想是...
您需要在绑定的UIElement上设置附加属性,传入您想要延迟的DP。这时,我已经有了附加属性的目标和要延迟的属性,所以我可以进行设置。但我必须等到绑定可用后才能使用Dispatcher实例化我的观察器类。如果不这样做,您将无法获取绑定表达式。
观察器类获取绑定并向DependencyProperty添加更新侦听器。在侦听器中,我设置一个计时器(如果我们尚未更新)或重置计时器。一旦计时器滴答声响起,我就会启动绑定表达式。
再次强调,它确实有效,但肯定需要清理。此外,您可以通过以下代码片段仅使用DP名称:
FieldInfo fieldInfo = instance.GetType()
.GetField(name,
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.FlattenHierarchy);
return (fieldInfo != null) ? (DependencyProperty)fieldInfo.GetValue(null) : null;
你可能需要在
name
后面添加“Property”,但与使用
x:Static
相比,这很容易。