c# - GUI 在 Dispatcher.BeginInvoke 或 Task.StartNew 时卡住

标签 c# wpf multithreading dispatcher taskfactory

注意:取决于 this quetion

我有一个像这样的 View 模型:

public class ViewModel {
    private readonly IPersonService _personService;
    private readonly ObservableCollection<SearchPersonModel> _foundedList;
    private readonly DispatcherTimer _timer;
    private readonly Dispatcher _dispatcher;
    private CancellationTokenSource _tokenSource;

    public SearchPatientViewModel(IPersonService personService) {
        _personService = personService;
        _foundedList = new ObservableCollection<SearchPersonModel>();
        _dispatcher = (/*CurrentApplication*/).Dispatcher;
        _timer = new DispatcherTimer(
            TimeSpan.FromMilliseconds(1000),
            DispatcherPriority.Normal,
            TimerCallBack,
            _dispatcher);
        _tokenSource = new CancellationTokenSource();
    }

    public string Term {
        get { return _term; }
        set {
            // implementing INotifyPropertyChanged
            if(_term== value)
                return;
            _term= value;
            OnPropertyChanged(() => Term);
            tokenSource.Cancel(); // canceling prev search query
            _timer.Stop(); // stop the timer to reset it
            // start it again to do a search query if user change not the term for 1000ms
            _timer.Start(); 
        }
    }

    private void TimerCallBack(object sender, EventArgs e) {
        _timer.Stop();
        _tokenSource = new CancellationTokenSource();
        var task = Task<IEnumerable<SearchPersonModel>>.Factory
            .StartNew(Search, _tokenSource.Token);
        _dispatcher.BeginInvoke((Action)(() => {
            _foundedList.Clear();
            foreach(var item in task.Result)
                _foundedList.Add(item);
        }), DispatcherPriority.Background);
    }

    private IEnumerable<SearchPersonModel> Search() {
        return _personService.DoSearch(this.Term);
    }

}

IPersonService 实现中,我这样做:

public class PersonService : IPersonService {
    public IEnumerable<SearchPersonModel> DoSearch(string term){
        System.Threading.Thread.Sleep(10000);
        return some-search-result;
    }
}

但是,我希望在执行搜索查询时,GUI 是免费的。但是它卡住了!你知道我的错误在哪里吗?

最佳答案

问题是评估 task.Result 将阻塞,直到查询完成。

最简单的选择可能是让 Search 方法在最后执行 _dispatcher.BeginInvoke 调用。

另一个选项(使用 C# 5 会变得更容易)是向任务添加延续,以便在任务完成时更新 UI。目前你会使用 Task.ContinueWith;对于 C# 5,您将使用 asyncawait

关于c# - GUI 在 Dispatcher.BeginInvoke 或 Task.StartNew 时卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10534290/

相关文章:

c# - 在 WPF 中使 StackPanel 方向水平

c# - 平滑滚动的垂直文本以获得进度

c# - 从其他 Xaml 文件绑定(bind)到 Usercontrol 中的元素

c++ - 多线程输入的基准 QTableWidget,奇怪的结果?

java - java中调用thread.start()后的语句流程是怎样的?

c# - 如何在 WPF 中的文本上创建多个笔划?

javascript - 在哪里放置小部件的脚本引用(部分页面)

c# - Xamarin ios : ABAddressbook. 创建始终为空,无法请求访问

c# - 如何在 WPF 项目中将 rdlc 文件添加到 ReportViewer

c++ - 为什么创建的线程数小于thread-max?