【问题标题】:UI still freezes using backgroundWorkerUI 仍然使用 backgroundWorker 冻结
【发布时间】:2013-01-25 16:43:55
【问题描述】:

我对 WPF 很陌生。我正在开发一个 PRISM 应用程序,并希望在更新可枚举时更新 UI。 我在我的模型视图中使用 backgroundWorker 来更新枚举。一切正常,直到它自己的枚举被更新然后用户界面冻结! 一位朋友告诉我,我也许可以使用 yield 关键字,但我不太明白。

代码如下:

public void ChangeCollection()
    {
        BackgroundWorker worker = new BackgroundWorker();

        // Set workers job
        worker.DoWork += (sender, e) =>
            {
                RunOnUIThread(() => IsBusy = true);
                e.Result = GetPrimes();
            };

        // On Complete
        worker.RunWorkerCompleted += (sender, e) =>
            {
                RunOnUIThread(() =>
                    {
                        IsBusy = false;

                        // HERE IS WHERE IT GETS STUCK
                        Numbers = new ObservableCollection<int>
                            ((IEnumerable<int>)e.Result);
                    });
            };

        // Start background operation
        worker.RunWorkerAsync();
    } 

    public ObservableCollection<int> Numbers 
    { 
        get {return _Numbers;} 
        set
        {
            _Numbers = value;
            RaisePropertyChanged(() => Numbers);
        }
    }

    public IEnumerable<int> GetPrimes()
    {
        List<int> primes = new List<int>();

        for (int i = 0; i < 100000; i++)
        {
            bool IsPrime = true;

            for (int j = 2; j < i; j++)
            {
                if (i % j == 0)
                    IsPrime = false;
            }

            if (IsPrime)
                primes.Add(i);
        }

        return primes;
    } 

任何建议将不胜感激!

谢谢, 暗里

【问题讨论】:

  • 什么绑定到Numbers?我怀疑如果您在 DataGridComboBox 中显示 9592 个项目,无论如何它都会很慢。
  • 您的代码看起来不错。您是否尝试过记录消息以确定挂起开始的时间点?
  • GetPrimes() 当然只是一个例子:) 我的绑定如下DataGridTextColumn Header="Numbers" Binding="{Binding Mode=OneWay}"
  • 除非您要在 UI 线程上添加和删除,否则我会使用 List 而不是 ObservableCollection。并让 GetPrimes 返回列表。

标签: c# wpf multithreading backgroundworker


【解决方案1】:

这里有几件事。 1)当包含它的对象被实例化时,应该创建您的工作人员及其代表。

public class ViewModel 
{
    BackgroundWorker _primeWorker;

    public ViewModel()
    {
        _primeWorker = new BackgroundWorker;

        _primeWorker.DoWork += ...
    }

    public void AddSomeNumbers()
    {
         if(_primerWorker.IsBusy == false)
              _primeWorker.RunWorkerAsync();
    }
}

2) 您的集合应该在包含它的对象被实例化时被实例化,以避免在使用此类的对象调用get 时引发空异常。

3) 添加这么多项目会导致速度变慢,因为每次添加数字时都会触发 UI 线程必须处理的事件。

此链接有更多信息可以帮助您。 http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

【讨论】:

    【解决方案2】:

    yield 在这里帮不了你。 RunWorkerCompleted 在 UI 线程上执行。显然实例化ObservableCollection&lt;int&gt; 需要很长时间。最简单的解决方案可能是将实例化也移动到后台线程 (DoWork)。它也可能是一个需要很长时间的 PropertyChanged 事件处理程序,在这种情况下它也应该在后台线程上运行。

    【讨论】:

    • 我不相信您可以从 UI 线程以外的线程更新 ObservableCollection&lt;T&gt;。不过我可能是错的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-28
    • 1970-01-01
    相关资源
    最近更新 更多