【问题标题】:How to resolve synchronisation problem with Helix Toolkit rendering on WPF composite render thread如何解决 WPF 复合渲染线程上 Helix Toolkit 渲染的同步问题
【发布时间】:2020-08-10 12:09:07
【问题描述】:

C#、WPF、Helix Toolkit。我正在尝试从HelixViewport3D 生成位图,但遇到了一些问题。

第一个问题是我找不到在屏幕外渲染的方法。网上对此有一些参考(例如here),据我所知,它没有内置解决方案。

作为一种不太理想的解决方法,我继续渲染到用户可以看到的屏幕上,目的是从该渲染图像创建位图。我现在有一个问题,如果我立即调用它,从屏幕上的内容导出的图像(例如使用Viewport3DHelper.SaveBitmap)是空白的。我理解这是因为 Helix Toolkit 正在 WPF 复合渲染线程中渲染图像,所以在我尝试抓取它的时候没有图像可以抓取,因为它还没有被渲染。

我不知道我可以订阅的“渲染完成”事件。有吗?

如果不是,解决方法可能是使用线程优先级来降低我的代码优先级,以便它在继续之前等待渲染完成?

<Window x:Class=".MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Test"
        xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf" xmlns:h="http://helix-toolkit.org/wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid>
            <h:HelixViewport3D x:Name="helixPlot" Width="450" Height="450"/>
        </Grid>
        <StackPanel Orientation="Horizontal">
            <Button Name ="btnGo" Height="25" Content="Render" VerticalAlignment="Bottom" Click="Go_Click"/>
            <Button Name ="btnTemp" Height="25" Content="Write PNG" VerticalAlignment="Bottom" Click="Test_Click"/>
        </StackPanel>
    </Grid>
</Window>

using System.Collections.Generic;
using System.Windows;
using HelixToolkit.Wpf;
using System.Windows.Media.Media3D;
using System.Windows.Media;

namespace Test
{

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

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void renderImages()
        {

            Foo bar = new Foo(); // create object with three 3D points

            DrawStuff(bar.points); // plot to helixViewport3D control ('points' = list of 3D points)
            helixPlot.CameraController.ZoomExtents();

            // This results in a blank image because image not yet rendered...
            Viewport3DHelper.SaveBitmap(helixPlot.Viewport, @"E:\test.png", null, 4, BitmapExporter.OutputFormat.Png);


        }
        private void DrawStuff(List<Point3D> points)
        {
            
            Point3DCollection dataList = new Point3DCollection();
            PointsVisual3D cloudPoints = new PointsVisual3D { Color = Colors.Red, Size = 5.0f };
            foreach (Point3D p in points)
            {
                dataList.Add(p);
            }
            cloudPoints.Points = dataList;

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

        }

        // When this is clicked we render image and (try to) save to file...
        private void Go_Click(object sender, RoutedEventArgs e)
        {
            renderImages();
        }

        // To demonstrate that the image export is not the problem.
        // This works if the image has been rendered already...
        private void Test_Click(object sender, RoutedEventArgs e)
        {
            Viewport3DHelper.SaveBitmap(helixPlot.Viewport, @"E:\test.png", null, 4, BitmapExporter.OutputFormat.Png);
        }
    }
}

【问题讨论】:

  • 你不能使用awaitasync 所以你知道DrawStuff 什么时候结束吗?
  • 没有。是 HelixToolkit 在不同的线程中执行异步执行。 DrawStuff() 只是调用它并继续。那就是问题所在。在渲染之前执行完成。
  • 我对@9​​87654332@ 不太熟悉,但您可能应该发布您想要用来执行异步操作的方法,因为我怀疑没有它有人可以为您提供解决方案。
  • 按要求添加。
  • 尝试发布一些可以编译的东西,这样试图帮助您的人就不必猜测所有内容:ThingshelixPlot 是什么helixViewPort3D 和@987654336 之间的关系是什么@?在调用DrawStuff 后可能有一个简单的修复方法,例如使用UpdateLayout()ApplyTemplate,但我不可能用你提供的内容对其进行测试......我检查了你提供的链接,但没有更多信息。

标签: c# wpf multithreading helix-3d-toolkit


【解决方案1】:

感谢this answer,我设法找到了解决方案:

Dispatcher.BeginInvoke(new Action(() =&gt; DoSomething()), DispatcherPriority.ContextIdle, null);

渲染完成后将调用该动作。

所以在你的情况下,你可以这样使用它:

private void renderImages()
{

    Foo bar = new Foo(); // create object with three 3D points

    this.DrawStuff(bar.points, SaveHelixPlotAsBitmap /*the action you want to perform once the rendering is done*/);    
}

private void DrawStuff(List<Point3D> points, Action renderingCompleted)
{
    //Draw everyting you need ...

    Dispatcher.BeginInvoke(renderingCompleted, DispatcherPriority.ContextIdle);
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    相关资源
    最近更新 更多