0

我的模板控件中的线程同步存在一些问题(尝试执行自动完成控件)

在我的控制范围内,我有以下代码:

protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var searchTextBox = GetTemplateChild("SearchTextBox") as TextBox;
        if (searchTextBox != null)
        {
            var searchDelegate = SearchAsync;

            Observable.FromEventPattern(searchTextBox, "TextChanged")
                .Select(keyup => searchTextBox.Text)
                .Where(TextIsLongEnough)
                .Throttle(TimeSpan.FromMilliseconds(500))
                .Do(ShowProgressBar)
                .SelectMany(searchDelegate)
                .ObserveOn(Dispatcher)
                .Subscribe(async results => await RunOnDispatcher(() =>
                                                                      {
                                                                          IsInProgress = false;
                                                                          SearchResults.Clear();
                                                                          foreach (var result in results)
                                                                          {
                                                                              SearchResults.Add(result);
                                                                          }
                                                                      }));
        }
    }

它抱怨在我的 ShowProgressBar 方法中,我试图访问由另一个线程编组的代码。

如果我注释掉 Throttle 和 ObserveOn(Dispatcher) 它工作得很好,但它不会像我想要的那样限制我的服务调用。

如果我只注释掉 Throttle 部分,什么都不会发生。

4

2 回答 2

1

每个依赖对象都要求仅在 Dispatcher 线程上对依赖属性进行任何更改。Throttle正在使用不同的调度程序,因此在后续组合器中对 UI 进行任何更改都会Do导致访问异常。

您可以通过以下方式解决此问题:

  1. 在对 Dispatcher 产生副作用的任何操作之前添加ObserveOnDispatcher 。可以选择在管道中使用另一个调度程序。
  2. 使用Dispatcher.Invoke通过调度程序执行副作用。例如, .Do(() => Dispatcher.Invoke(new Action(ShowProgressBar)))
于 2012-09-22T20:38:24.057 回答
1

Asti 的想法是正确的,但更好的方法是IScheduler向 Throttle 提供参数:

// NB: Too lazy to look up real name 
.Throttle(TimeSpan.FromMilliseconds(500), CoreDispatcherScheduler.Instance) 

这将在 UI 线程(包括您的 ShowProgressBar)上进行下面的操作,直到 SelectMany。

于 2012-09-22T21:37:55.950 回答