Rac*_*hel 5 c# wpf timer mvvm propertychanged
我想知道PropertyChanged当用户在输入文本时暂停时是否可以引发事件TextBox?或者更具体地说,我想X在用户停止在TextBox中键入数秒后运行一个方法.
例如,我有一个带有TextBox的表单,没有别的.用户在TextBox中键入1-9位Id值,相当资源密集的后台进程加载记录.
我不想使用,UpdateSouceTrigger=PropertyChanged因为这会导致资源密集型后台进程在键入字符时运行,因此9位ID号从这些进程中的9个开始.
我也不想使用,UpdateSourceTrigger=LostFocus因为表单上没有任何其他内容可以使TextBox失去焦点.
那么有没有办法让我的后台进程只有在用户输入ID号时暂停后才会运行?
dle*_*lev 10
设置UpdateSourceTrigger=PropertyChanged,然后每次属性更改时,启动计时器以延迟您的延迟.如果在计时器滴答之前再次更改属性,则取消旧计时器并启动新计时器.如果计时器确实打勾,那么您知道该属性在X秒内没有改变,您可以启动后台进程.
小智 8
准备代码转储.
我用WPF假行为(一个附加的DP就像一个行为)这样做了.此代码有效,但它不漂亮,可能会导致泄漏.可能需要用弱引用等替换所有引用.
这是Behavior类:
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
/// <summary>
/// An Attached <see cref="DependencyProperty"/> of type <see cref="DependencyProperty"/> defined on <see cref="DependencyObject">DependencyObject instances</see>.
/// </summary>
public static readonly DependencyProperty TargetPropertyProperty = DependencyProperty.RegisterAttached(
TargetPropertyPropertyName,
typeof(DependencyProperty),
typeof(DelayedUpdateBehavior),
new FrameworkPropertyMetadata(null, OnTargetPropertyChanged)
);
/// <summary>
/// The name of the <see cref="TargetPropertyProperty"/> Attached <see cref="DependencyProperty"/>.
/// </summary>
public const string TargetPropertyPropertyName = "TargetProperty";
/// <summary>
/// Sets the value of the <see cref="TargetPropertyProperty"/> on the given <paramref name="element"/>.
/// </summary>
/// <param name="element">The <see cref="DependencyObject">target element</see>.</param>
public static void SetTargetProperty(DependencyObject element, DependencyProperty value)
{
element.SetValue(TargetPropertyProperty, value);
}
/// <summary>
/// Gets the value of the <see cref="TargetPropertyProperty"/> as set on the given <paramref name="element"/>.
/// </summary>
/// <param name="element">The <see cref="DependencyObject">target element</see>.</param>
/// <returns><see cref="DependencyProperty"/></returns>
public static DependencyProperty GetTargetProperty(DependencyObject element)
{
return (DependencyProperty)element.GetValue(TargetPropertyProperty);
}
/// <summary>
/// Called when <see cref="TargetPropertyProperty"/> changes
/// </summary>
/// <param name="d">The <see cref="DependencyObject">event source</see>.</param>
/// <param name="e"><see cref="DependencyPropertyChangedEventArgs">event arguments</see></param>
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
/// <summary>
/// An Attached <see cref="DependencyProperty"/> of type <see cref="int"/> defined on <see cref="DependencyObject">DependencyObject instances</see>.
/// </summary>
public static readonly DependencyProperty MillisecondsProperty = DependencyProperty.RegisterAttached(
MillisecondsPropertyName,
typeof(int),
typeof(DelayedUpdateBehavior),
new FrameworkPropertyMetadata(1000)
);
/// <summary>
/// The name of the <see cref="MillisecondsProperty"/> Attached <see cref="DependencyProperty"/>.
/// </summary>
public const string MillisecondsPropertyName = "Milliseconds";
/// <summary>
/// Sets the value of the <see cref="MillisecondsProperty"/> on the given <paramref name="element"/>.
/// </summary>
/// <param name="element">The <see cref="DependencyObject">target element</see>.</param>
public static void SetMilliseconds(DependencyObject element, int value)
{
element.SetValue(MillisecondsProperty, value);
}
/// <summary>
/// Gets the value of the <see cref="MillisecondsProperty"/> as set on the given <paramref name="element"/>.
/// </summary>
/// <param name="element">The <see cref="DependencyObject">target element</see>.</param>
/// <returns><see cref="int"/></returns>
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它的示例:
<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>
Run Code Online (Sandbox Code Playgroud)
这个要点是......
您在绑定的UIElement上设置附加属性,传入您希望延迟的DP.在这一点上,我有附加属性的目标和要延迟的属性,所以我可以设置.我必须等到绑定可用,所以我必须使用Dispatcher在设置数据绑定后实例化我的观察者类.不能这样做,你不能抓住绑定表达式.
watcher类获取绑定并向DependencyProperty添加更新侦听器.在监听器中,我设置了一个计时器(如果我们没有更新)或重置计时器.一旦Timer滴答,我就会触发绑定表达式.
它再次起作用,但肯定需要清理.此外,您可以通过其名称使用DP以及以下代码段:
FieldInfo fieldInfo = instance.GetType()
.GetField(name,
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.FlattenHierarchy);
return (fieldInfo != null) ? (DependencyProperty)fieldInfo.GetValue(null) : null;
Run Code Online (Sandbox Code Playgroud)
您可能需要将"Property"添加到"Property"上name,但与使用相比,这很容易x:Static.
如果您使用 .NET 4.5 或更高版本,则可以使用Binding 的Delay属性。这真的很简单:
<TextBox Text="{Binding Name, Delay=500, UpdateSourceTrigger=PropertyChanged}"/>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3269 次 |
| 最近记录: |