WriteableBitmap和线程 [英] WriteableBitmap and threads

查看:94
本文介绍了WriteableBitmap和线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

友好的问候!

WriteableBitmap是DispatcherObject,只有创建Dispatcher的线程可以访问DispatcherObject直。要从创建DispatcherObject的线程以外的线程访问DispatcherObject
on,我们需要在与DispatcherObject关联的Dispatcher上调用Invoke或BeginInvoke。并且委托将在该线程上执行,因此渲染线程将被阻止。


WriteableBitmap is DispatcherObject, only the thread that the Dispatcher was created on may access the DispatcherObject directly. To access a DispatcherObject from a thread other than the thread the DispatcherObject was created on, we need to call Invoke or BeginInvoke on the Dispatcher the DispatcherObject is associated with. And the delegate will be executed on that thread, so the render thread will block.

没有办法在线程中使用WriteableBitmap(没有锁定UI,这会使线程的使用毫无意义),即使我们不将它用作前端缓冲区,并且实际上它不是我们想要的UI的一部分使用它。

There is no way to use WriteableBitmap in threads (without locking the UI, which makethe usage of threads pointless), even if we don't use it as a front buffer and is actually not really part of the UI at the moment we want to work with it.

这是一个老问题,我从 2010 中写的帖子中复制了第一部分,7年前^^

It's an old problem, i copied the first part from a post written in 2010, 7 years ago ^^

我想知道现在有什么解决方案吗?

I'm wondering is there is any solution now ?

问题很简单: 

The problem is simple : 


  1. 显示在UI上的前端缓冲区
  2. 后备缓冲区(前端缓冲区的副本)
  3. 我们不时会将后台缓冲区复制到前台缓冲区以更新显示。

简单,对吗?但是我们不能使用WriteableBitmap来实现它,所以现在有一个线程安全等价于WriteableBitmap而不必将它复制到int []并基本上重新实现了我们自己的(线程安全)版本的WriteableBitmap吗?

Easy, right ? But we can't use WriteableBitmap to do it, so is there now a threadsafe equivalent to WriteableBitmap without having to do a copy of it to an int[] and basically reimplementing our own (threadsafe) version of WriteableBitmap ?

谢谢你< 3

推荐答案

Hi Ker,

Hi Ker,

WriteableBitmap内置了多线程功能。我可能在这里遗漏了一些东西,但它看起来就像它就在那里。 

WriteableBitmap has the multithread capability built into it. I may be missing something here, but it look to me like it is all there. 

我很遗憾无法理解您遇到的实际问题,所以这里有一些示例代码可以解决您的问题。

I unfortunately could not understand the actual issue you are experiencing, so here is some sample code that may resolve your problem.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Input;

namespace WriteableBitmapDemo
{
    class Program
    {
        static WriteableBitmap writeableBitmap;
        static Window w;
        static Image i;

        [STAThread]
        static void Main(string[] args)
        {
            i = new Image();
            RenderOptions.SetBitmapScalingMode(i, BitmapScalingMode.NearestNeighbor);
            RenderOptions.SetEdgeMode(i, EdgeMode.Aliased);

            w = new Window();
            w.Content = i;
            w.Show();

            writeableBitmap = new WriteableBitmap(
                (int)w.ActualWidth, 
                (int)w.ActualHeight, 
                96, 
                96, 
                PixelFormats.Bgr32, 
                null);

            i.Source = writeableBitmap;

            i.Stretch = Stretch.None;
            i.HorizontalAlignment = HorizontalAlignment.Left;
            i.VerticalAlignment = VerticalAlignment.Top;

            i.MouseMove += new MouseEventHandler(i_MouseMove);
            i.MouseLeftButtonDown += 
                new MouseButtonEventHandler(i_MouseLeftButtonDown);
            i.MouseRightButtonDown += 
                new MouseButtonEventHandler(i_MouseRightButtonDown);

            w.MouseWheel += new MouseWheelEventHandler(w_MouseWheel);

            Application app = new Application();
            app.Run();
        }

        // The DrawPixel method updates the WriteableBitmap by using
        // unsafe code to write a pixel into the back buffer.
        static void DrawPixel(MouseEventArgs e)
        {
            int column = (int)e.GetPosition(i).X;
            int row = (int)e.GetPosition(i).Y;

            // Reserve the back buffer for updates.
            writeableBitmap.Lock();

            unsafe
            {
                // Get a pointer to the back buffer.
                int pBackBuffer = (int)writeableBitmap.BackBuffer;

                // Find the address of the pixel to draw.
                pBackBuffer += row * writeableBitmap.BackBufferStride;
                pBackBuffer += column * 4;

                // Compute the pixel's color.
                int color_data = 255 << 16; // R
                color_data |= 128 << 8;   // G
                color_data |= 255 << 0;   // B

                // Assign the color data to the pixel.
                *((int*) pBackBuffer) = color_data;
            }

            // Specify the area of the bitmap that changed.
            writeableBitmap.AddDirtyRect(new Int32Rect(column, row, 1, 1));

            // Release the back buffer and make it available for display.
            writeableBitmap.Unlock();
        }

        static void ErasePixel(MouseEventArgs e)
        {
            byte[] ColorData = { 0, 0, 0, 0 }; // B G R

            Int32Rect rect = new Int32Rect(
                    (int)(e.GetPosition(i).X), 
                    (int)(e.GetPosition(i).Y), 
                    1, 
                    1);

            writeableBitmap.WritePixels( rect, ColorData, 4, 0);
        }

        static void i_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            ErasePixel(e);
        }

        static void i_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DrawPixel(e);
        }

        static void i_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                DrawPixel(e);
            }
            else if (e.RightButton == MouseButtonState.Pressed)
            {
                ErasePixel(e);
            }
        }

        static void w_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            System.Windows.Media.Matrix m = i.RenderTransform.Value;

            if (e.Delta > 0)
            {
                m.ScaleAt(
                    1.5, 
                    1.5, 
                    e.GetPosition(w).X, 
                    e.GetPosition(w).Y);
            }
            else
            {
                m.ScaleAt(
                    1.0 / 1.5, 
                    1.0 / 1.5, 
                    e.GetPosition(w).X, 
                    e.GetPosition(w).Y);
            }

            i.RenderTransform = new MatrixTransform(m);
        }
    }
}

此示例来自关于可写类的MSDN文档


这篇关于WriteableBitmap和线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆