C# XAML GUI 由于 API 函数而冻结

本文关键字:函数 冻结 API 由于 XAML GUI | 更新日期: 2023-09-27 18:33:36

我有一个程序,它通过API将股票报价推送给我。该程序还有一个用 XAML 制作的前端,当该程序运行时冻结(即处理 API 发送给我的信息)。我尝试使用Dispatcher.Invoke和/或BackgroundWorker 并且已经阅读了大量线程,但无法将其解冻。也许我只是做错了什么。我在这里附上了相关代码。希望有人能帮忙。

    private void QuoteUpdate(QuoteInfo info)
    {
        BackgroundWorker bwQuoteUpdate = new BackgroundWorker();
        bwQuoteUpdate = new BackgroundWorker();
        bwQuoteUpdate.WorkerSupportsCancellation = true;
        bwQuoteUpdate.DoWork += bwQuoteUpdate_DoWork;            
        bwQuoteUpdate.RunWorkerAsync(info);         
    }
    private void bwQuoteUpdate_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() =>
            {
                QuoteInfo info = e.Argument as QuoteInfo;
                //logical functions and work are here
            }));
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show("Error in QuoteUpdate: " + ex.Message, "Exception Thrown");
        }
    }        

C# XAML GUI 由于 API 函数而冻结

尽管您正在创建一个旨在在后台线程上执行长时间运行的任务的BackgroundWorker,但仍会将所有处理调度回 UI 线程。

private void bwQuoteUpdate_DoWork(object sender, DoWorkEventArgs e)
{
    // Code here runs on background thread.
    Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() =>
    {
        // Code here runs on UI thread.
    }));
}

您需要做的是首先在后台线程上执行计算,但不更新任何 UI 组件;而是将所有结果存储在局部变量中。然后,完成后,使用 Dispatcher.Invoke 将控件调度回 UI 线程,并使用存储在局部变量中的结果来更新 UI。

例如:

private void bwQuoteUpdate_DoWork(object sender, DoWorkEventArgs e)
{
    // Code here runs on background thread.
    QuoteInfo info = e.Argument as QuoteInfo;
    string result = PerformLongRunningProcessing(info);
    Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() =>
    {
        // Code here runs on UI thread.
        this.resultTextBox.Text = result;
    }));
}

是的,你做错了什么。计算应该单独在线程中完成,只添加 UI 更改应该在Dispatcher.Invoke中完成。

如果通过 INotifyPropertyChange 使用数据绑定,则完全删除Dispatcher.Invoke,因为封送对 UI 线程的更改是自动完成的。

试试

Dispatcher.BeginInvoke(...)