在文本框进入暂停期间抚养PropertyChanged事件? [英] Raising a PropertyChanged event during a Pause in TextBox entry?

查看:133
本文介绍了在文本框进入暂停期间抚养PropertyChanged事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有可能提出一个的PropertyChanged 事件当用户暂停,而键入文本文本框 ?或者更具体地说,我希望用户在 X 秒运行的方法停止键入一个文本框。

I was wondering if it's possible to raise a PropertyChanged event when the user pauses while typing text into a TextBox? Or more specifically, I want to run a method X seconds after the user stops typing in a TextBox.

例如,我有一个文本框,并没有其他的形式。在1-9位ID值到文本框的用户类型,一个相当资源密集型后台进程加载的记录。

For example, I have a form with a TextBox and nothing else. The user types in a 1-9 digit Id value into the TextBox, a fairly resource-intensive background process loads the record.

我不想使用 UpdateSouceTrigger =的PropertyChanged ,因为这会导致资源密集型后台进程运行,每当一个字符被类型化,所以一个9位数的ID编号开始关闭这些进程9。

I do not want to use the UpdateSouceTrigger=PropertyChanged because that would cause the resource-intensive background process to run whenever a character gets typed, so a 9-digit ID number starts off 9 of these processes.

我也不想用 UpdateSourceTrigger =引发LostFocus ,因为没有什么别的表格上,使文本框失去焦点。

I also don't want to use UpdateSourceTrigger=LostFocus because there is nothing else on the form to make the TextBox lose focus.

在ID号码打字的时候那么有没有办法使我的后台进程只有用户后,运行将暂停?

So is there a way to cause my background process to run only after the user pauses when typing in the Id number?

推荐答案

prepare为code-转储。

Prepare for code-dump.

我曾与一个WPF假行为(附加DP行为类似的行为)做到了这一点。这code的作品,但它不是pretty,它可能会导致泄漏。可能需要替换所有弱引用的参考文献等。

I've done this with a WPF Fake Behavior (an attached DP that acts like a behavior). This code works, but it isn't pretty and it may result in leaks. Probably need to replace all the references with weak references, etc.

下面是行为类:

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;
            }
        }
    }
}

而这里的它是如何使用的例子:

And here's an example of how it is used:

<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>

此的要点是...

The gist of this is...

您设置绑定的UIElement的附加属性,传递DP你要延迟。在这一点上,我不得不推迟附加属性和属性的目标,这样我就可以设置好了。我必须等到结合是可用的,所以我必须使用数据绑定调度员已成立后,以实例我守望类。未能做到这一点,你不能抢绑定前pression。

You set the attached property on the bound UIElement, passing in the DP you wish to delay. At this point, I have the target of the attached property and the property to be delayed, so I can set things up. I do have to wait until the binding is available, so I have to use the Dispatcher to instantiate my watcher class after databinding has been set up. Fail to do this and you can't grab the binding expression.

在观察者类抓住结合,并增加了一个更新监听到的DependencyProperty。在听者,我设置了一个定时器(如果我们还没有更新)或复位定时器。一旦计时器滴答声,我火了结合前pression。

The watcher class grabs the binding and adds an update listener to the DependencyProperty. In the listener, I set up a timer (if we haven't updated) or reset the timer. Once the Timer ticks, I fire off the binding expression.

再次,它的工作原理,但它肯定需要清理。此外,您还可以通过刚才的名称使用DP具有以下code片断:

Again, it works, but it definitely needs cleanup. Also, you can just use the DP via its name with the following code snippet:

FieldInfo fieldInfo = instance.GetType()
                             .GetField(name, 
                                 BindingFlags.Public | 
                                 BindingFlags.Static | 
                                 BindingFlags.FlattenHierarchy);
return (fieldInfo != null) ? (DependencyProperty)fieldInfo.GetValue(null) : null;

您可能需要钉财产到名称,但是比起使用 X,很容易:静态。

You might have to tack "Property" onto name, but that's easy compared to using x:Static.

这篇关于在文本框进入暂停期间抚养PropertyChanged事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆