如何解决 WPF 复合渲染线程上 Helix Toolkit 渲染的同步问题
How to resolve synchronisation problem with Helix Toolkit rendering on WPF composite render thread
C#、WPF,Helix Toolkit。我正在尝试从 HelixViewport3D
生成位图,但遇到了一些问题。
第一个问题是我找不到渲染离屏的方法。网上有一些参考资料(例如 here),据我所知它没有内置解决方案。
作为一种不太理想的解决方法,我已经开始渲染到用户可以看到它的屏幕,目的是从该渲染图像创建位图。我现在有一个问题,如果我立即调用它,从屏幕上的内容导出的图像(例如使用 Viewport3DHelper.SaveBitmap
)是空白的。我理解这是因为Helix Toolkit正在WPF复合渲染线程中渲染图像,所以在我试图抓取它的时候没有图像可以抓取,因为它还没有被渲染。
我不知道可以订阅的 'render complete' 活动。有吗?
如果不是,解决方法可能是使用线程优先级来降低我的代码的优先级,以便它在继续之前等待渲染完成?
<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);
}
}
}
感谢 this answer:
我找到了解决方案
Dispatcher.BeginInvoke(new Action(() => 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);
}
C#、WPF,Helix Toolkit。我正在尝试从 HelixViewport3D
生成位图,但遇到了一些问题。
第一个问题是我找不到渲染离屏的方法。网上有一些参考资料(例如 here),据我所知它没有内置解决方案。
作为一种不太理想的解决方法,我已经开始渲染到用户可以看到它的屏幕,目的是从该渲染图像创建位图。我现在有一个问题,如果我立即调用它,从屏幕上的内容导出的图像(例如使用 Viewport3DHelper.SaveBitmap
)是空白的。我理解这是因为Helix Toolkit正在WPF复合渲染线程中渲染图像,所以在我试图抓取它的时候没有图像可以抓取,因为它还没有被渲染。
我不知道可以订阅的 'render complete' 活动。有吗?
如果不是,解决方法可能是使用线程优先级来降低我的代码的优先级,以便它在继续之前等待渲染完成?
<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);
}
}
}
感谢 this answer:
我找到了解决方案
Dispatcher.BeginInvoke(new Action(() => 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);
}