【问题标题】:WPF Threading Grab BagWPF 穿线抓包
【发布时间】:2011-06-15 14:55:22
【问题描述】:

我开发了一个有趣的 WPF 控件,它目前正在减慢我的整个应用程序的速度:) 在我的自定义控件上,我有一个图像控件,每次发生后端事件时我都需要更新它。此后端事件每秒触发两次(非常快)。当事件触发时,我需要从 3rd 方控件中拉出 Bitmap 对象,转换为 BitmapSource 对象,然后将其绑定到我的 Image 控件。每次触发我的事件时,我都会在 ThreadPool 中排队一个新的工作项。然后该项目将获取位图并在后台工作对象中进行转换。每次事件触发时都会执行此操作。我正在使用调度程序通过 BeginInvoke 更新我的图像控制源,但我仍然得到一个无响应的应用程序。请让我知道我可以做些什么来使这个过程更好地执行并帮助我的应用程序更具响应性:

这是我的活动中的代码:

void inSight_ResultsChanged(object sender, EventArgs e)
        {

            ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessEvent), ((InSightViewer)this.DataContext).CvsDisplay);
        }

这是委托的代码:

void ProcessEvent(object display)
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            bw.RunWorkerAsync(display);

        }

这是我的后台工作人员 DoWork 事件中的代码:

void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            3rdPartyControl displayControl = new 3rdPartyControl();

            displayControl.ImageHost = (ImgHost)e.Argument;


            Bitmap b = displayControl.GetBitmap();

            var mBitmap = b.GetHbitmap();
            BitmapSource bs;

            try
            {
                bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                           mBitmap,
                           IntPtr.Zero,
                           Int32Rect.Empty,
                           BitmapSizeOptions.FromEmptyOptions());

                bs.Freeze();
            }
            catch (System.Exception ex) { throw ex; }
            finally
            {
                DeleteObject(mBitmap);
            }

            e.Result = bs;
        }

这是 RunWorkerCompleted 事件中的代码:

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, (ThreadStart)delegate()
        {
            this.imgSource.Source = (BitmapSource)e.Result;
        });
}

【问题讨论】:

  • BackgroundWorker 将在后台线程中完成它的工作。在单独的线程(通过 ThreadPool)上创建 BackgroundWorker 似乎也很不寻常。有什么理由吗?
  • 尝试注释掉 begininvoke 语句,看看应用是否仍然无响应。如果是,那么它一定是上面未显示的某些代码在 GUI 线程上运行。后端是否使用任何需要 STA 的 COM 互操作?
  • 第三方控件是 .NET winforms 控件,但我确信它在后台使用了一些 COM/GDI 技术。
  • 检查问题是否是COM泵送:在后台worker启动后放置一个Thread.Sleep(10000),以防止GUI线程泵送。然后在 RunWorkerCompleted 里面放一个断点,看看是否到达。
  • 这似乎没有什么不同。如果我用一个简单的计数器文本框模拟整个过程,每次触发后端事件时都会更新,那么一切都会完美运行——我从执行的第一分钟就得到了所有 120 次更新——当我引入图像控件、位图转换和图像源时绑定应用出去吃午饭了。

标签: wpf multithreading image backgroundworker threadpool


【解决方案1】:
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
        Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, (ThreadStart)delegate()
        {
            this.imgSource.Source = (BitmapSource)e.Result;
        });
}

System.Windows.Threading.DispatcherPriority.ApplicationIdle 表示在应用程序空闲时处理操作。

如果应用程序总是很忙而且从不空闲怎么办?请求将被排队,应用程序变慢。

但是我没有对此进行测试,因为我没有您的应用程序的源代码。

【讨论】:

    猜你喜欢
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    相关资源
    最近更新 更多