gpt4 book ai didi

c# - 在内存中渲染 Livecharts 图表并另存为图像

转载 作者:行者123 更新时间:2023-11-30 23:11:57 25 4
gpt4 key购买 nike

我正在尝试执行以下操作:

  • 在内存中创建 Livechart 笛卡尔图表
  • 将图表添加到网格
  • 将标签添加到同一个网格
  • 将网格添加到 Viewbox
  • 将 Viewbox 渲染为 PNG
  • 将 PNG 保存到磁盘

为了允许 UI 响应,上面的代码应该从后台的不同线程运行。

无论这看起来多么简单,我一直在努力寻找合适的工作解决方案。以下问题是相关的:

  • Livechart(位于 Viewbox 内)需要时间来呈现
  • 因此,在尝试将其保存为图像之前,需要给图表一些时间来完成渲染
  • 我找到了使用 HwndSource 的代码,但它并非一直有效(大约 95% 的时间有效)。如果没有 HwndSource 修改,它永远不会工作(总是得到一个没有任何内容的图表)
  • 在不同的 UI 线程中运行 Run() 函数不起作用,因为我收到以下错误消息:WPF Dispatcher {“调用线程无法访问此对象,因为另一个线程拥有它。”}

所以我的问题是:

  • 等待 Livechart/Grid/ViewBox 组合完成渲染后再将其保存为图像的正确方法是什么?也许利用 Loaded 事件?请注意,我曾尝试插入它,但由于遇到“线程”问题而无法使其正常工作。
  • 如何在不同的 UI 线程中运行整个流程?

代码见下

public void Run()
(
//Create Livechart which is a child of a Grid control
Grid gridChart = Charts.CreateChart();
//Creates a ViewBox control which has the grid as its child
Viewbox viewBox = WrapChart(gridChart,1400,700);
//Creates and saves the image
CreateAndSaveImage(viewBox ,path,name);
)

下面是创建 Viewbox 并将网格添加为子项的函数

public Viewbox viewBox WrapChart(Grid grid,int width,int height)
{

chart.grid.Width = width;
chart.grid.Height = height;

viewbox.Child = chart.grid;

viewbox.Width = width;
viewbox.Height = height;
viewbox.Measure(new System.Windows.Size(width, height));
viewbox.Arrange(new Rect(0, 0, width, height));
viewbox.UpdateLayout();

}

下面的函数创建并保存图像

public void CreateAndSaveImage(Viewbox viewbox,string folderPath,string fileName)
{
var x = HelperFunctions.GetImage(viewbox);
System.IO.FileStream stream = System.IO.File.Create(folderPath + fileName);
HelperFunctions.SaveAsPng(x, stream);
stream.Close();
}

以下代码将 View 框渲染为图像。请注意,这是我能找到的唯一等待图表加载完成的代码。我不知道它是如何工作的,但它在 95% 的时间里都有效。有时图表仍未完成加载。

public static RenderTargetBitmap GetImage(Viewbox view)
{

using (new HwndSource(new HwndSourceParameters())
{
RootVisual =
(VisualTreeHelper.GetParent(view) == null
? view
: null)
})
{

Size size = new Size(view.ActualWidth, view.ActualHeight);
if (size.IsEmpty)
return null;


int actualWidth = Convert.ToInt32(size.Width);
int requiredWidth = Convert.ToInt32(size.Width * 1);

int actualHeight = Convert.ToInt32(size.Height);
int requiredHeight = Convert.ToInt32(size.Height * 1);

// Flush the dispatcher queue
view.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => { }));

var renderBitmap = new RenderTargetBitmap(requiredWidth, requiredHeight,
96d * requiredWidth / actualWidth, 96d * requiredHeight / actualHeight,
PixelFormats.Pbgra32);


DrawingVisual drawingvisual = new DrawingVisual();
using (DrawingContext context = drawingvisual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(view), null, new Rect(new Point(), size));
context.Close();
}

renderBitmap.Render(view);
renderBitmap.Freeze();

return renderBitmap;
}


}

以下代码将位图作为图片保存到文件

public static void SaveAsPng(BitmapSource src, Stream outputStream)
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));

encoder.Save(outputStream);
}

下面的代码是我用来在不同线程中运行整个过程的代码。请注意,它不起作用,因为我收到以下错误消息:

WPF Dispatcher {“The calling thread cannot access this object because a different thread owns it.”}.

请注意,如果我正常执行 Run()(没有任何单独的线程)它会工作,但有时图表无法正确呈现(如前所述)。

Thread thread = new Thread(() =>
{
Run();

System.Windows.Threading.Dispatcher.Run();

});

thread.SetApartmentState(ApartmentState.STA);
thread.Start();

最佳答案

尝试为图表调用此行:

    this.chart.Model.Updater.Run(false, true);

此行更新图表并在保存到图像时始终可见。

关于c# - 在内存中渲染 Livecharts 图表并另存为图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44411801/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com