OxyPlot 导出图片及 WPF 元素导出为图片的方法

目录

OxyPlot 导出图片及 WPF 元素导出为图片的方法

一、OxyPlot 自带导出方法

二、导出 WPF 界面元素的方法

三、通过附加属性来使用

独立观察员 2022 年 2 月 26 日

最近有个需求,就是将 OxyPlot 图形导出图片。经过尝试,本文记录三种方法:1、OxyPlot 自带导出方法;2、网上找的导出 WPF 界面元素的方法;3、基于方法 2 的附加属性调用方式。下面将逐一介绍。

一、OxyPlot 自带导出方法

同事说这个用 OxyPlot 官方提供的导出方法即可,我在 Demo 中试了一下,是可以的,代码如下:

/// <summary>
/// 曲线数据源(OxyPlot)
/// </summary>
public PlotModel PlotModel { get; set; } = new PlotModel();ExportPngCmd ??= new RelayCommand(o => true, async o =>
{var pngExporter = new PngExporter { Width = (int)PlotModel.Width, Height = (int)PlotModel.Height, };//string exportPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Export");string exportPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "Export");if (!Directory.Exists(exportPath)){Directory.CreateDirectory(exportPath);}pngExporter.ExportToFile(PlotModel, Path.Combine(exportPath, $"{DateTime.Now:yyyyMMdd_HHmmss}.png"));await ConfirmBoxHelper.ShowMessage(DialogVm, "导出完成", 3);
});

各种导出方法可以在 OxyPlot 官方文档(https://oxyplot.readthedocs.io/en/latest/export/index.html)中查看

这里用到的是导出到 PNG 文件的方法,不过用的 NuGet 包最新版(2.1.0)中,PngExporter 中并没有 Background 属性:

所以如果图表没有设置背景色的话,导出背景为透明的,可以设置上:

PlotModel.Background = OxyColor.Parse("#FFFFFF");

总的来说,这个方法简单快捷,而且对 MVVM 友好。不过也有缺点,就是如果有些元素(比如说标题、坐标轴文字)不是使用 OxyPlot 图表控件来生成的话,则导出的图片就不会包含它们了:

我在实际项目中确实遇到了这个问题,所以需要寻找其它方法,我们接着看。

二、导出 WPF 界面元素的方法

首先给出能够导出任意 WPF 界面元素(FrameworkElement)为图片的方法,来源于网络,地址在方法注释中已给出,略作修改,代码如下:

using System;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;namespace WPFTemplateLib.WpfHelpers
{/// <summary>/// 导出图片帮助类/// </summary>public class ExportPicHelper{/// <summary>/// 保存为图片/// (修改自:https://blog.csdn.net/dhl11/article/details/108621634)/// </summary>/// <param name="frameworkElement"> 可视化元素,可以是 Grid、StackPanel 等类型的所有可视化元素 </param>/// <param name="filePath"> 文件路径 </param>/// <param name="errorMsg"> 错误消息 </param>/// <returns> 是否成功 </returns>public static bool SaveToImage(FrameworkElement frameworkElement, string filePath, out string errorMsg){try{errorMsg = string.Empty;FileStream fs = new FileStream(filePath, FileMode.Create);RenderTargetBitmap bmp = new RenderTargetBitmap((int)frameworkElement.ActualWidth,(int)frameworkElement.ActualHeight,1 / 96, 1 / 96, PixelFormats.Default);bmp.Render(frameworkElement);BitmapEncoder encoder = new TiffBitmapEncoder();encoder.Frames.Add(BitmapFrame.Create(bmp));encoder.Save(fs);fs.Close();return true;}catch (Exception ex){Console.WriteLine($" 保存图片异常:{ex}");errorMsg = ex.Message;return false;}}}
}

用这个方法首先要给界面元素起个名字,我这里给图表区用户控件元素起了个 “Plot” 名称:

这样在后台代码中就可以用来导出了:

private void ExportPicBtn_OnClick(object sender, RoutedEventArgs e)
{ExportPicture(Plot);
}/// <summary>
/// 导出图片
/// </summary>
/// <param name="element">xaml 里面的某个可视化元素对象 </param>
private void ExportPicture(FrameworkElement element)
{SaveFileDialog saveFileDialog = new SaveFileDialog{Filter = "PNG 文件 (*.png)|*.png|JPG 文件 (*.jpg)|*.jpg|BMP 文件 (*.bmp)|*.bmp|GIF 文件 (*.gif)|*.gif|TIF 文件 (*.tif)|*.tif"};if (saveFileDialog.ShowDialog() == true){string dir = System.IO.Path.GetDirectoryName(saveFileDialog.FileName);if (!Directory.Exists(dir)){Directory.CreateDirectory(dir);}string filePath = saveFileDialog.FileName;if (File.Exists(filePath)){File.Delete(filePath);}bool success = ExportPicHelper.SaveToImage(element, filePath, out string errorMsg);if (success){MessageBox.Show($"导出成功");}else{MessageBox.Show($" 导出失败 {errorMsg}");}}
}

可以看到想要导出的内容都导出成功了:

优点是显而易见的,缺点就是导出逻辑要写在后台代码中,对 MVVM 模式不友好。下面来看看本人修改的使用附加属性的方案,尝试解决这个问题。

三、通过附加属性来使用

还是先给出代码:

using System;
using System.IO;
using System.Windows;
using WPFTemplateLib.WpfHelpers;namespace WPFTemplateLib.Attached
{/// <summary>/// 导出图片附加属性类/// </summary>public class ExportPicAttached : DependencyObject{#region 是否开始导出public static bool GetIsExporting(DependencyObject obj){return (bool)obj.GetValue(IsExportingProperty);}public static void SetIsExporting(DependencyObject obj, bool value){obj.SetValue(IsExportingProperty, value);}/// <summary>/// 是否正在导出(运行时设置为 true 则将附加的元素导出为图片)/// </summary>public static readonly DependencyProperty IsExportingProperty =DependencyProperty.RegisterAttached("IsExporting", typeof(bool), typeof(ExportPicAttached),new PropertyMetadata(false, OnIsExportingValueChanged));private static void OnIsExportingValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){FrameworkElement element = d as FrameworkElement;if (element == null)return;if ((e.NewValue as bool?) == false)return;try{string exportPath = GetExportPath(d);if (string.IsNullOrEmpty(exportPath)){exportPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),"Export");}if (!Directory.Exists(exportPath)){Directory.CreateDirectory(exportPath);}string filePath = Path.Combine(exportPath, $"{DateTime.Now:yyyyMMddHHmmss}.png");bool success = ExportPicHelper.SaveToImage(element, filePath, out string errorMsg);if (success){MessageBox.Show($"导出成功");}else{Console.WriteLine($" 导出失败:{errorMsg}");MessageBox.Show($" 导出失败 {errorMsg}");}}catch (Exception ex){Console.WriteLine($" 导出异常:{ex}");MessageBox.Show($" 导出异常:{ex.Message}");}finally{// 此处设置为 false 没什么用,还是需要业务层在设置为 true 前先设置为 false 才行。SetIsExporting(d, false);}}#endregion#region 导出文件夹public static string GetExportPath(DependencyObject obj){return (string)obj.GetValue(ExportPathProperty);}public static void SetExportPath(DependencyObject obj, string value){obj.SetValue(ExportPathProperty, value);}/// <summary>/// 导出文件夹路径/// </summary>public static readonly DependencyProperty ExportPathProperty =DependencyProperty.RegisterAttached("ExportPath", typeof(string), typeof(ExportPicAttached), new PropertyMetadata(string.Empty));#endregion}
}

ExportPicAttached 类中包含两个附加属性,一个是导出文件夹路径 ExportPath,一个是是否开始导出 IsExporting。当 IsExporting 被设置为 true 则开始导出,如果导出文件夹路径没被设定,则导出到桌面文件夹,然后就是调用方案二中出现的 ExportPicHelper.SaveToImage 方法。

使用方法就是在要导出的元素上设置上这两个附加属性,然后把值进行绑定:

在 ViewModel 中,先设定导出路径,然后把 IsExporting 置为 true 即可开始导出:

也是能正常导出的:

这个方案结合了前两个方案的优点,既能导出所有想要的内容,又对 MVVM 友好。

缺点就是导出的控制有点奇怪,需要先将 IsExporting 置为 false,不然第二次就导出不了了。尝试了在附加属性逻辑中自动置为 false,但是好像值传递不到 VM 中的相关绑定属性中,有了解解决方法的朋友们请不吝赐教。

全文完,感谢阅读,祝大家天天开心。

WPF

让 WPF 的 RadioButton 支持再次点击取消选中的功能

WPF DataGrid 如何将被选中行带到视野中

WPF 触屏事件后触发鼠标事件的问题及 DataGrid 误触问题

WPF DataGrid 通过自定义表头模拟首行固定

WPF ComboBox 使用 ResourceBinding 动态绑定资源键并支持语言切换

【翻译】WPF 中附加行为的介绍 Introduction to Attached Behaviors in WPF

WPF 使用 Expression Design 画图导出及使用 Path 画图

WPF MVVM 弹框之等待框

解决 WPF 绑定集合后数据变动界面却不更新的问题(使用 ObservableCollection)

WPF 消息框 TextBox 绑定新数据时让光标和滚动条跳到最下面

真・WPF 按钮拖动和调整大小

WPF MVVM 模式下的弹窗

WPF 让一组 Button 实现 RadioButton 的当前样式效果

WPF 原生绑定和命令功能使用指南

WPF 用户控件的自定义依赖属性在 MVVM 模式下的使用备忘

在WPF的MVVM模式中使用OCX组件

第三方库使用

WPF 表格控件 ReoGrid 的简单使用

OxyPlot.WPF 公共属性一览

OxyPlot.Wpf 图表控件使用备忘

OxyPlot 导出图片及 WPF 元素导出为图片的方法相关推荐

  1. CSS关于图片填充指定元素或者用图片做背景

    在实际开发中,经常会遇到需要将某图片填充到指定的div中或者将图片作为某个div的背景图片,然后还需要在图片的不同层面嵌入不同的操作.一般,要达成对应的效果的操作方式多样,但想要在不同浏览器上或者不同 ...

  2. 元素导出为图片与pdf的几种方式

    文章目录 原生方法将canvas元素导出为图片 使用库将html元素导出为图片: 使用库将html元素导出为pdf 原生方法将canvas元素导出为图片 使用原生javascript的方法将canva ...

  3. html图片自动适应,css如何让图片自适应?

    要使图片能够自适应显示,我们一般可以通过设置CSS样式,让图片作为父元素的背景图片,再设置相关属性来实现.下面我们来看一下使用css设置图片自适应的方法. css设置图片自适应示例: HTML代码: ...

  4. Vue中使用html2canvas和jspdf插件实现导出pdf(自定义html样式可带图片)并下载

    场景 若依前后端分离版手把手教你本地搭建环境并运行项目: 若依前后端分离版手把手教你本地搭建环境并运行项目_BADAO_LIUMANG_QIZHI的博客-CSDN博客_若依前后端分离文档 在上面搭建起 ...

  5. .net 导出excel_使用 EasyPOI 优雅导出Excel模板数据(含图片)

    作者:星悬月 blog.csdn.net/u012441819/article/details/96828044 EasyPOI功能如同名字Easy,主打的功能就是容易,让一个没接触过POI的人员可以 ...

  6. Angular导出功能(excel导出功能、文件数据流导出功能、图片的下载导出功能)

    Angular导出功能(excel导出功能.文件数据流导出功能.图片的下载导出功能) 场景1:(直接返回网络地址进行导出的excel) 后台返回的是 : "http://192.168.0. ...

  7. JS导出PDF插件(支持中文、图片使用路径)

    JS导出PDF插件(支持中文.图片使用路径) 原文:JS导出PDF插件(支持中文.图片使用路径) 在WEB上想做一个导出PDF的功能,发现jsPDF比较多人推荐,遗憾的是不支持中文,最后找到pdfma ...

  8. python 打印数组变量_使用Python将数组的元素导出到变量中(unpacking)

    下面就为大家分享一篇使用Python将数组的元素导出到变量中(unpacking),具有很好的参考价值,希望对大家有所帮助.一起过来看看吧 最近工作中遇到一个问题,需要利用Python将数组(list ...

  9. 使用Magicodes.IE.Excel完成Excel图片的导入和导出

    说明 本章教程主要说明如何使用Magicodes.IE.Excel进行图片的导入导出. 要点 配置DTO进行Excel图片导出 配置DTO进行Excel图片导入 图片导入导出特性说明 ExportIm ...

最新文章

  1. 《MSSQL2008技术内幕:T-SQL语言基础》读书笔记(下)
  2. python遍历目录,获取指定文件
  3. MYSQL-交换表中2行2字段的值
  4. 抓包分析360浏览器和360搜索配对使用的安全性-WEB服务端分析
  5. 《推荐系统笔记(八)》GBDT和XgBoost的原理(内含详细数学推导)
  6. 剑指offer之替换空格
  7. Characterizing stochastic time series with ordinal networks
  8. zookeeper 客户端 zkCli.sh 的使用 查看节点
  9. Linux Shall命令入门
  10. PXA300平台2D图形加速器性能测试与分析
  11. 百度地图api自定义marker图片不显示问题
  12. linux读usb蓝牙数据,嵌入式Linux下USB蓝牙设备驱动.pdf
  13. 教你win10更新失败怎么解决,win10系统更新失败怎么办
  14. Unity3D——游戏序列化
  15. 【阿里云-容器】阿里云容器服务Kubernetes版快速入门
  16. 为什么 1 KB = 1024 B? 1 MB = 1024 KB?
  17. UNITY 使用代码更换地形中草的贴图
  18. tf.control_dependencies与tf.identity组合详解
  19. 【RocketMQ】延迟消息(延迟队列)
  20. 将二维数组中的行列互换

热门文章

  1. 给初学者的 RxJava2.0 教程 (八)
  2. spark集群详细搭建过程及遇到的问题解决(四)
  3. MathType插入带序号公式的两种方法
  4. Android在第三方应用程序系统应用尽早开始,杀死自己主动的第三方应用程序,以重新启动...
  5. 《程序员》杂志2011年第5期.pdf 下载链接 首发。
  6. 真希望永远用不到这些代码
  7. ubuntu+php环境下的Memcached 安装方法
  8. He Fei ,First ,Good Luck
  9. [转]table中设置tr行间距
  10. 2016 校园招聘求职经历(二)