【问题标题】:WPF: how to invoke a method in a separate thread with a delay timeWPF:如何在具有延迟时间的单独线程中调用方法
【发布时间】:2012-05-18 09:59:21
【问题描述】:

我有一个TextBox,用户可以在其中输入搜索词。它绑定到我的view-model 中的string Term 属性。我想在内容更改时进行搜索查询。但我想在一个单独的线程中使用 delay 进行查询。

例如当用户输入一个字母时,我想等待 0.3 秒,如果用户在这段时间内(0.3 秒)更改输入,则计时器重置并再次启动。否则,我会启动一个新线程并执行搜索查询。在查询执行期间,如果用户再次更改术语,则中止上一个查询并重新开始。

我知道如何在带有线程和Timer 类的 Windows 窗体中执行此操作。但我是 WPF 的新手,我正在搜索是否有为 WPF 线程功能指定的方法(或者可能是一种性能更好的方法)。

你有什么想法吗?你能帮帮我吗?

【问题讨论】:

    标签: c# wpf multithreading c#-4.0 dispatcher


    【解决方案1】:

    您可能想查看来自 Microsoft 的 Reactive Extensions。 Rx 提供了一种在经过一定延迟后将这些类型的事件聚合为单个事件的方法。

    Phil Haack(前 Microsoft)在他的 blog 上有一篇很好的文章,他谈到了节流功能。

    【讨论】:

      【解决方案2】:

      您可以使用DispatcherTimer。在每次按键时,如果计时器已经在运行,则停止计时器,然后启动它。我相信(你应该检查一下!)这会重置它。

      如果它触发了,那么您将获取文本框中的当前值并开始在单独的线程中执行操作(例如,使用 Task.Factory.StartNew,如果您使用的是 .NET 4,或 BackgroundWorker,或者只是创建一个新线程)。

      基本上,这将“新线程”部分与“我真的想做某事”部分分开,将所有内容都保留在 UI 线程上,直到您决定真正确实想要做某事(并且您知道要使用的值)。

      【讨论】:

      • 好吧,你是 Jon Skeet,我听不懂你在说什么!!! :D 我对WPF 很陌生,所以我只有 187 分。您的解决方案似乎比 Robaticus 的解决方案更好,但我需要一些代码来理解它:D 我在想,我应该有 one 线程(而不是在每个查询中都有一个新线程,这似乎是更好的性能),然后运行或中止它。这是真的吗?另外,很高兴与您交谈。非常感谢。
      • @king.net:你不想中止线程,但如果输入发生变化,你总是可以忽略结果。阅读DispatcherTimer 了解这部分内容,然后单独处理线程。
      • 好吧,你是对的。我读到了msdn.microsoft.com/en-us/library/…>,我明白你刚才在说什么。但在开始编码之前只有一个问题:我可以从CallBack 中停止DispatcherTimer 吗?
      • @king.net: 停止进一步的“滴答声”?绝对的。
      • @king.net:一旦您发出查询,您就根本不需要计时器(除非用户键入另一个字符)。但是您通常不会中止查询 - 您只会忽略结果。当然,如果您的查询确实支持取消,那就太好了 - 但我们需要了解更多有关搜索的信息,才能知道如何在这方面为您提供帮助。
      【解决方案3】:

      这只是建立在 Jon Skeets 所说的之上。把复选标记给他。 .stop() 似乎重置了timer

      public MainWindow()
      {
          InitializeComponent();
      
          backgroundWorker1 = new BackgroundWorker();
          backgroundWorker1.WorkerReportsProgress = true;
          backgroundWorker1.WorkerSupportsCancellation = true;
          backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
          backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
          backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
      
          dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
          dispatcherTimer.Interval = new TimeSpan(0, 0, 4);
      }
      
      public string Input
      {
          get { return input; }
          set
          {
              if (value == input) return;
              value = value.Trim();
              input = value;
              NotifyPropertyChanged("Input");
      
              if (backgroundWorker1.IsBusy) backgroundWorker1.CancelAsync();
              dispatcherTimer.Stop();                
              dispatcherTimer.Start();
          }
       }
      
      private void dispatcherTimer_Tick(object sender, EventArgs e)
      {
          dispatcherTimer.Stop();
          if (!backgroundWorker1.IsBusy)
          {
              backgroundWorker1.RunWorkerAsync(Input);
          }
      }
      

      【讨论】:

      • 正如约翰所说,如果我们有一个支持取消的查询,BackgroundWorker 是不必要的。不过谢谢
      • 就我而言,这不是一个查询。
      • 我做第一部分。但是还有另一个问题。你能看看完成吗:stackoverflow.com/questions/10534290/…
      猜你喜欢
      • 2011-03-30
      • 1970-01-01
      • 2012-06-25
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多