Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将BitmapImage引用传递给BackgroundWorker.DoWork_C#_Windows Phone 7_Backgroundworker_Pass By Reference - Fatal编程技术网

C# 如何将BitmapImage引用传递给BackgroundWorker.DoWork

C# 如何将BitmapImage引用传递给BackgroundWorker.DoWork,c#,windows-phone-7,backgroundworker,pass-by-reference,C#,Windows Phone 7,Backgroundworker,Pass By Reference,我有一个从资源流构造的位图图像。我需要将其发送到后台工作线程进行一些后期处理。但工作线程似乎无法访问位图数据,并在我的LoadImage第一行中获取System.UnauthorizedAccessException。如何解决这个问题?我还需要将处理后的位图传输回UI(XAML)以显示。如何正确地做到这一点 ImageLoader.RunWorkerAsync(albumArtImage); private void LoadImage(object sender, DoWor

我有一个从资源流构造的位图图像。我需要将其发送到后台工作线程进行一些后期处理。但工作线程似乎无法访问位图数据,并在我的LoadImage第一行中获取System.UnauthorizedAccessException。如何解决这个问题?我还需要将处理后的位图传输回UI(XAML)以显示。如何正确地做到这一点

    ImageLoader.RunWorkerAsync(albumArtImage);

    private void LoadImage(object sender, DoWorkEventArgs e)
    {
        WriteableBitmap wb = new WriteableBitmap((BitmapImage)e.Argument);
        wb.Resize(AppWidth, AppHeight, WriteableBitmapExtensions.Interpolation.Bilinear);
        var wb2 = WriteableBitmapExtensions.Convolute(wb, WriteableBitmapExtensions.KernelGaussianBlur3x3);            
        e.Result = wb2;
    }

    private void LoadImageCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        AlbumBackground.ImageSource = (WriteableBitmap)e.Result;
    }

需要从UI线程调用WriteableBitmap。这只是你无法绕过的实用程序的一个限制

从MSDN:

WriteableBitmap类使用两个缓冲区。后台缓冲区在系统内存中分配,并累积当前未显示的内容。前端缓冲区在系统内存中分配,包含当前显示的内容。渲染系统将前缓冲区复制到视频内存中进行显示

两个线程使用这些缓冲区。用户界面(UI)线程生成UI,但不将其显示在屏幕上。UI线程响应用户输入、计时器和其他事件。一个应用程序可以有多个UI线程。渲染线程从UI线程合成和渲染更改。每个应用程序只有一个渲染线程

UI线程将内容写入后台缓冲区。渲染线程从前缓冲区读取内容并将其复制到视频内存。使用更改的矩形区域跟踪对后缓冲区的更改

后台工作人员的替代方案:

你需要在UI线程上这样做,这是无法回避的事实。但是您可以将它推到队列的末尾,这样用户就不会太注意到它

试着这样做:

public static void RunDelayedOnUiThread(Action action)
{
     Deployment.Current.Dispatcher.BeginInvoke(() =>
     {
         var timer = new DispatcherTimer 
                     { 
                         Interval = TimeSpan.FromMilliseconds(1) 
                     };
         timer.Tick += (sender, args) =>
         {
             timer.Stop();
             action();
         };

         timer.Start();
     });
}
这应该足够了,这样您的图像处理(在本例中是传递的操作)将放在等待在UI线程上处理的队列的末尾。图像处理仍然会在UI线程工作时阻塞它,但至少其他所有事情都应该先完成

工作原理:

当您调用BeginInvoke时,您的操作被放置在调度程序队列的末尾,当UI线程从当前正在执行的操作(运行代码)中释放出来时,将运行该操作。但是,因为您可以一次又一次地调用BeginInvoke,然后图像处理将阻止dispatcher队列中的其他内容,所以我们希望将其再次放在后面。这就是调度员进来的地方。从MSDN:

计时器不保证在时间间隔发生时准确执行,但保证在时间间隔发生之前不执行。这是因为Dispatcher操作与其他操作一样放置在Dispatcher队列上。调度程序操作的执行时间取决于队列中的其他作业及其优先级

所以只要我们给它一毫秒的间隔就足够把它推回到队列的末尾

在WindowsPhone7上,这可能仍然会阻止某些触摸事件,但至少不会阻止页面呈现


在Windows Phone 8上,“全景”、“透视”和“长列表选择器”都响应非UI线程上的输入,因此您在那里会更安全一些。

这对我来说很有效。在将位图传递给backgroundWorker之前,我将其冻结,并且不会引发异常

BackgroundWorker bw = new BackgroundWorker();
BitmapSource bmpCanvas;
BitmapSource bmpRef;

List<object> arg = new List<object>();
arg.Add(bmpCanvas);
arg.Add(bmpRef);
bmpCanvas.Freeze();
bmpRef.Freeze();

bw.RunWorkerAsync(arg);

我不同意位图修改是一个仅限于用户界面的过程。我已经实现了一些代码(可能太长了,无法发布),这些代码在单独的后台工作人员中为单独的位图计算修改参数,在计算完成时将数据存储在一些数组中(用于像素分配),并将一些布尔值设置为“while”和“if”开关。在另一个BGW中,每个位图处理一个,我有一个循环等待计算完成布尔触发。触发时,辅助工作线程从阵列复制结果,然后重新启动计算线程以开始下一帧的计算。。。(我有没有提到这是一部动画??)。然后,这些BGW使用tempbit.SetPixel(x,y,color)//将复制的参数应用于临时位图(每个原始位图一个)//注意:(可能有一种更有效的方法可以使用…)。一旦位图被更新,就会抛出更多的布尔开关(同时BGW在下一帧开始计算)。然后在最后一个BGW上,我实现了等待每个单独的临时位图更新的代码。当他们这样做时,我复制位图,并重新启动图像更新BGWs(这种布尔结构防止任何对象重叠)。复制完所有图像后,我将组合图像,然后更新picturebox.Image,然后重新启动循环(这将需要一些布尔逻辑和goto语句或重新启动异步中继方法)。因此,基本上,只要不允许两个backgroundworker对象访问共享的第三个对象,就不会引发异常

用外行的话说,我有单独的BGW用于wach单独的任务,并实现逻辑以防止任何线程重叠。这仍然允许BGW类的异步优势,而无需所有的跨线程和繁忙的检查


快乐编码

这听起来像是图像处理只能在UI线程中完成?那不是很好…是的,这就是它的意思。非常感谢!我一定要试一试!嗨,乔尔,我试过这个方法。你能检查一下这是否是预期的结果吗?看起来实际显示处理后的图像所需的时间更长,但其他UI更新得比以前更早。在解决方案之前,页面标题等已处理的背景图像在切换到页面2秒后显示。应用溶液后,标题etc显示1.3秒,处理后的背景大约为2.3~2.4秒。有时,整个页面在大约2秒的时间内同时显示。如果这听起来是对的,也许这是最好的选择
void bw_DoWork(object sender, DoWorkEventArgs e)
{
   List<object> argu = e.Argument as List<object>;

   BitmapSource bCanvas = (BitmapSource)argu[0];
   BitmapSource bref = (BitmapSource)argu[1];
   // doing something with those images...
   bCanvas.Freeze();
   e.Result = bCanvas;
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
   BitmapSource bmpCanvas = (BitmapSource)e.Result;

   image.Source = bmpCanvas;
}