延迟触发自定义事件

时间:2011-07-12 09:48:50

标签: c# wpf event-handling

我想扩展TextBox控件,因此它将触发具有指定延迟的自定义事件。

这是我到目前为止的代码:

    public class DelayTextBox : TextBox
{
    private Timer _delayTimer;
    private int _threshold = 1000;

    public DelayTextBox()
    {
        _delayTimer = new Timer(_threshold);
        _delayTimer.Elapsed += new ElapsedEventHandler(_delayTimer_Elapsed);
    }

    public int Delay
    {
        set { _threshold = value; }
    }

    private void _delayTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        _delayTimer.Stop();
        RaiseDelayedTextChangedEvent();
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        _delayTimer.Stop();
        _delayTimer.Start();
    }

    private static readonly RoutedEvent DelayedTextChangedEvent = EventManager.RegisterRoutedEvent(
    "DelayedTextChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DelayTextBox));

    public event RoutedEventHandler DelayedTextChanged
    {
        add { AddHandler(DelayedTextChangedEvent, value); }
        remove { RemoveHandler(DelayedTextChangedEvent, value); }
    }

    private void RaiseDelayedTextChangedEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(DelayTextBox.DelayedTextChangedEvent);
        RaiseEvent(newEventArgs);
    }
}

问题在于每当我触发RaiseDelayedTextChangedEvent()时,我都会收到异常,告诉我

  

'调用线程因为不同而无法访问此对象   线程拥有它。'

此处抛出异常:

private void RaiseDelayedTextChangedEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(DelayTextBox.DelayedTextChangedEvent);
        RaiseEvent(newEventArgs);
    } <---- Here

2 个答案:

答案 0 :(得分:2)

那是因为Timer在不同的线程中运行,并且无法从该线程修改UI(就像你的异常所说)。请尝试使用DispatcherTimer。您可以在此处了解详情:http://code.dortikum.net/2008/08/06/timer-vs-dispatchertimer-in-wpf/

答案 1 :(得分:0)

您需要使用调度程序在STA线程中引发事件。

本文解释了您遇到的线程问题http://www.switchonthecode.com/tutorials/working-with-the-wpf-dispatcher

private void RaiseDelayedTextChangedEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(DelayTextBox.DelayedTextChangedEvent);

        this.Dispatcher.BeginInvoke(
                System.Windows.Threading.DispatcherPriority.Normal,
                (UpdateTheUI)delegate(RoutedEventArgs eArgs)
                {
                   RaiseEvent(eArgs);
                }, newEventArgs );

    }