循环内的异步操作-如何保持执行控制权?

问题描述

关注this one的问题。

我正在尝试生成并保存一系列图像。渲染是由Helix Toolkit完成的,我被告知使用WPF复合渲染线程。这会引起问题,因为它异步执行。

最初的问题是我无法保存给定的图像,因为当时我尚未尝试渲染该图像。上面的答案通过将“保存”操作放在优先级较低的Action内,从而提供了一种解决方法,从而确保了渲染首先完成。

这对于一张图像来说很好,但是在我的应用程序中,我需要多张图像。就目前而言,我无法控制事件的顺序,因为它们是异步发生的。我正在使用For循环,无论渲染和保存图像的进度如何,该循环都将继续。我需要一张一张地生成图像,并有足够的时间进行渲染和保存,然后再开始下一张。

我尝试将延迟放入循环中,但这会导致其自身的问题。例如,在代码中注释的async await会引起跨线程问题,因为数据是在与呈现渲染所在的线程不同的线程上创建的。我尝试设置一个简单的延迟,但是那样只会锁定所有内容-我认为部分原因是我正在等待的保存操作的优先级非常低。

由于不能在GUI中使用单个HelixViewport3D控件,因此不能简单地将其视为一批独立的不相关的异步任务。这些图像必须顺序生成。

我确实尝试了一种递归方法,其中SaveHelixPlotAsBitmap()调用DrawStuff(),但是效果不是很好,而且这也不是一个好方法。

我尝试在每个循环上设置一个标志(“忙”),并等待其重置后再继续操作,但这仍然行不通-再次由于异步执行。同样,我尝试使用计数器使循环与已生成但遇到类似问题的图像数量保持同步。

我似乎陷入了我不想参与的线程和异步操作的困境。

我该如何解决?

class Foo {
    public List<Point3D> points;
    public Color PointColor;
    public Foo(Color col) { // constructor creates three arbitrary 3D points
        points = new List<Point3D>() { new Point3D(0,0),new Point3D(1,new Point3D(0,1) };
        PointColor = col;
    }
}

public partial class MainWindow : Window
{
    int i = -1; // counter
    public MainWindow()
    {
        InitializeComponent();
    }
    private void Go_Click(object sender,RoutedEventArgs e) // STARTING POINT
    {
        // Create list of objects each with three 3D points...
        List<Foo> bar = new List<Foo>(){ new Foo(Colors.Red),new Foo(Colors.Green),new Foo(Colors.Blue) };

        foreach (Foo b in bar)
        {

            i++;
            DrawStuff(b,SaveHelixPlotAsBitmap); // plot to helixViewport3D control ('points' = list of 3D points)

            // This is fine the first time but then it runs away with itself because the rendering and image grabbing
            // are asynchronous. I need to keep it sequential i.e.
            // Render image 1 -> save image 1
            // Render image 2 -> save image 2
            // Etc.

        }
    }
    private void DrawStuff(Foo thisFoo,Action renderingCompleted)
    {

        //await System.Threading.Tasks.Task.Run(() =>
        //{

        Point3DCollection dataList = new Point3DCollection();
        PointsVisual3D cloudPoints = new PointsVisual3D { Color = thisFoo.PointColor,Size = 5.0f };
        foreach (Point3D p in thisFoo.points)
        {
            dataList.Add(p);
        }
        cloudPoints.Points = dataList;

        // Add geometry to helixPlot. It renders asynchronously in the WPF composite render thread...
        helixViewport3D.Children.Add(cloudPoints);
        helixViewport3D.CameraController.ZoomExtents();

        // Save image (low priority means rendering finishes first,which is critical)..
        Dispatcher.BeginInvoke(renderingCompleted,DispatcherPriority.ContextIdle);

        //});

    }
    private void SaveHelixPlotAsBitmap()
    {
        Viewport3DHelper.SaveBitmap(helixViewport3D.Viewport,$@"E:\test{i}.png",null,4,BitmapExporter.OutputFormat.Png);
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)