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

Render Livecharts Chart in Memory and Save as Image

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

以上内容应 运行 来自后台的不同线程,以允许 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();   
}

以下代码将视图框呈现为图像。请注意,这是我能找到的唯一等待图表加载完成的代码。我不知道它是如何工作的,但它在 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.”}.

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

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

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

});

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

尝试为图表调用此行:

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

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