目录
一 关闭最小化
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.WindowState = FormWindowState.Minimized;
}
}
二 退出程序接口
System.Environment.Exit(0);
三 最小化或关闭时隐藏到系统托盘
1 添加托盘图标控件NotifyIcon
直接从工具箱中拖动添加即可。
2 添加(重写)窗口尺寸变动函数Form1_Resize
private void Form1_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized) //最小化到系统托盘
{
NotifyIcon1.Visible = true; //显示托盘图标
this.Hide(); //隐藏窗口
}
}
3 添加(重写)关闭窗口事件
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//注意判断关闭事件Reason来源于窗体按钮,否则用菜单退出时无法退出!
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true; //取消"关闭窗口"事件
this.WindowState = FormWindowState.Minimized;//使关闭时窗口向右下角缩小的效果
NotifyIcon1.Visible = true;
this.Hide();
return;
}
}
4 添加双击托盘图标事件(双击显示窗口)
private void NotifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
NotifyIcon1.Visible = false;
this.Show();
WindowState = FormWindowState.Normal;
this.Focus();
}
PS:解决了设置“关闭时隐藏到系统托盘”时,点击“退出”菜单也无法退出的问题。——无论是用 this.Close();
还是 Application.Exit();
都无法退出!——解决办法是,在关闭窗口事件中判断关闭原因/来源 (e.CloseReason)
,若为 CloseReason.UserClosing
则为点击了窗口右上角的关闭按钮,否则可能是点击了"退出"菜单,则不执行隐藏到托盘的程序。(详见STEP3的if判断)
5 添加托盘图标的右键菜单
本节内容。
(具体代码略)
"退出"菜单:Application.Exit();
"显示窗口"菜单:参考STEP4
四 子窗口最大最小按钮
窗体的 FormBorderStyle
设置为 sizable
才会出现最大/小化按钮。
五 DataGridView
1 点击事件
DataGridView点击事件并不总是触发,使用 CellClick事件而不是 CellContentClick ,因为当单击任何 部分时触发该事件(不只是它里面的内容)。
2 自动宽度AutoSizeColumnsMode
1、AllCells 调整列宽,以适合该列中的所有单元格的内容,包括标题单元格。
2、AllCellsExceptHeader 调整列宽,以适合该列中的所有单元格的内容,不包括标题单元格。
3、ColumnHeader 调整列宽,以适合列标题单元格的内容。
4、DisplayedCells 调整列宽,以适合当前屏幕上显示的行的列中的所有单元格的内容,包括标题单元格。
5、DisplayedCellsExceptHeader 调整列宽,以适合当前屏幕上显示的行的列中的所有单元格的内容,不包括标题单元格。
6、Fill 调整列宽,使所有列的宽度正好填充控件的显示区域,只需要水平滚动保证列宽在DataGridViewColumn.MinimumWidth 属性值以上。相对列宽由相对 DataGridViewColumn.FillWeight 属性值决定。
7、None 列宽不会自动调整。
8、NotSet 列的大小调整行为从 DataGridView.AutoSizeColumnsMode 属性继承。
整体自动宽度:Autosizecolumnsmode = file;
,特定列固定宽度:AutoSizeMode = None
。
3 不显示第一列
RowHeadersVisible = false
六 C# TreeView 右键菜单
方法一:
在winform中,添加一个contextMenuStrip1,设置TreeView的属性ContextMenuStrip为contextMenuStrip1,并为这个contextMenuStrip1添加几个菜单项,点击每个菜单项,实现其click事件,然后添加treeivew的nodemouseclick事件,类似如下代码:
//右键菜单
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button != MouseButtons.Right) return;
if (e.Node.Parent == null || e.Node == null) return;
treeView1.SelectedNode = e.Node;
contextMenuStrip1.Show(tv_Roots, e.X, e.Y);
}
void contextMenuStripItem_Click(object sender, EventArgs e)//编辑飞行段
{
}
方法二:不同节点对应不同的右键菜单
private void tvOneRoot_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button != MouseButtons.Right) return;
if (e.Node == null) return; //无节点
if (e.Node.Level == 0) return;
int nodeType = GetNodeTypeByGuid(e.Node.Name);
tvOneRoot.SelectedNode = e.Node;
InitcmsOneRout(nodeType);
cmsOneRout.Show(tvOneRoot, e.X, e.Y);
}
/// <summary>
/// 初始化cmsOneRoot 从nodetype
/// </summary>
/// <param name="nodetype"></param>
private void InitcmsOneRout(int nodetype)
{
cmsOneRout = new ContextMenuStrip();
if (nodetype == -1)
{
ToolStripMenuItem tmiEditRoutStation = new ToolStripMenuItem("编辑飞行站点");
tmiEditRoutStation.Click += new EventHandler(tmiEditRoutStation_Click);
cmsOneRout.Items.Add(tmiEditRoutStation);
ToolStripMenuItem tmiMoveRouteStation = new ToolStripMenuItem("更改位置");
tmiMoveRouteStation.Click += new EventHandler(tmiMoveRouteStation_Click);
cmsOneRout.Items.Add(tmiMoveRouteStation);
ToolStripMenuItem tmiDeleRouteStation = new ToolStripMenuItem("删除飞行站点");
tmiDeleRouteStation.Click += new EventHandler(tmiDeleRouteStation_Click);
cmsOneRout.Items.Add(tmiDeleRouteStation);
}
else if (nodetype == 0)
{
ToolStripMenuItem tmiEditRout = new ToolStripMenuItem("编辑飞行段属性");
tmiEditRout.Click += new EventHandler(tmiEditRout_Click);
cmsOneRout.Items.Add(tmiEditRout);
ToolStripMenuItem tmiDeleteRout = new ToolStripMenuItem("删除飞行段");
tmiDeleteRout.Click += new EventHandler(tmiDeleteRout_Click);
cmsOneRout.Items.Add(tmiDeleteRout);
}
else if (nodetype == 1)
{
}
else if (nodetype == 2)
{
}
else
{
}
}
void tmiEditRout_Click(object sender, EventArgs e)//编辑飞行段
{
string routId = tvOneRoot.SelectedNode.Name;
RouteParameter rp = GetRouteParaByGuid(routId);
FrmPointProperty frm = new FrmPointProperty(rp, 0, 1);
frm.OnRoutInfoUpdated += new FrmPointProperty.DelegateRouteInfoUpdated(frm_OnRoutInfoUpdated);
frm.ShowDialog();
}
七 c# winform窗体如何设置才可以不能随意拖动大小
https://www.cnblogs.com/janghe/p/7843677.html
八 滚动条查看PictureBox的大图片
PictureBox自身没有滚动条,看不到大图片,而Panel自带滚动条,可以用Panel给PictureBox加上滚动条,设置Panel属性AutoScroll为true,设置PictureBox属性SizeMode为AutoSize,这样就可以用滚动条来看PictureBox中的大图片。
九 DockPanel
1 不显示关闭按钮
示例:
imageShow = ImageShow.GetInstance();
imageShow.Show(this.dockPanel1);
imageShow.CloseButton = false;
imageShow.CloseButtonVisible = false;
2 不可浮动
拖动:如果你想使你的子窗体可以任意拖动,那么你在设置子窗体的DockAreas属性时,保持默认值,不要修改;
固定:只需设置你窗体的DockAreas为Document就行了。
3 判断Dockpanel中存在多少个子窗体或Contents
foreach (DockContent frm in this.dockPanel1.Contents)
{
//这样设置后,所有的继承与DockContent的窗体都会被计算在内的
}
4 子窗体布局
在用DockPanel做MDI程序时,子窗体的初始化布局的实现,比如停靠左边,“日”字型的,有两种方法:
Me.DockPanel1.DockLeftPortion = 0.15'停靠区域占窗口比例
方法1:
frm1.show(DockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockTop)
frm1.Show(DockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockLeft)
frm1.DockAreas = WeifenLuo.WinFormsUI.Docking.DockAreas.DockLeft
frm2.Show(DockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockBottom)
frm2.Show(DockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockLeft)
frm2.DockAreas = WeifenLuo.WinFormsUI.Docking.DockAreas.DockLeft
方法2:
frm1.Show(DockPanel1, WeifenLuo.WinFormsUI.Docking.DockState.DockLeft)
frm1.DockAreas = WeifenLuo.WinFormsUI.Docking.DockAreas.DockLeft
frm2.Show(frm1.Pane, WeifenLuo.WinFormsUI.Docking.DockAlignment.Bottom, 0.618)
frm2.DockAreas = WeifenLuo.WinFormsUI.Docking.DockAreas.DockLeft
相对于方法1,方法2可以设置两个子窗口的高度比例,更好用些。
5 示例
C# 开源控件DockPanel 使用心得:https://blog.csdn.net/gd6321374/article/details/78059501
C#实现浮动和多标签窗体解决方案—使用Dockpanel:https://blog.csdn.net/zhangyuehua123/article/details/6861401
十 父子窗口传值
Winform中如何实现父窗体传递数据到子窗体并刷新子窗体:https://www.cnblogs.com/qufly/p/3433195.html
十一 子窗口间传值
https://www.cnblogs.com/wuhuacong/archive/2012/07/06/2578198.html
十二 Log4net
AssemblyInfo.cs:
using System.Resources; # line 1
[assembly: NeutralResourcesLanguage("zh-Hans")] # line 38
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
App.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<!--log4net配置start-->
<log4net>
<logger name="Log">
<level value="INFO" />
<param name="Encoding" value="utf-8" />
<appender-ref ref="RollingLog" />
</logger>
<logger name="Err">
<level value="ERROR" />
<appender-ref ref="RollingErr" />
</logger>
<appender name="RollingLog" type="log4net.Appender.RollingFileAppender">
<file value="Log\" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd'.txt'" />
<!--不加utf-8编码格式,中文字符将显示成乱码-->
<param name="Encoding" value="utf-8" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="记录时间:%d 线程ID:[%thread]- 操作信息:%m%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="INFO" />
</filter>
</appender>
<appender name="RollingErr" type="log4net.Appender.RollingFileAppender">
<file value="Err\" />
<param name="Encoding" value="utf-8" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd'.txt'" />
<!--不加utf-8编码格式,中文字符将显示成乱码-->
<param name="Encoding" value="utf-8" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="记录时间:%d 线程ID:[%thread]- 错误描述:%m%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ERROR" />
<param name="LevelMax" value="ERROR" />
</filter>
</appender>
</log4net>
<!--log4net配置end-->
LogHelp.cs:
using log4net;
using System.Diagnostics;
using System.Reflection;
namespace Log_Helper
{
public class LogHelp
{
private static readonly ILog logInfo = LogManager.GetLogger("Log");
private static readonly ILog logErr = LogManager.GetLogger("Err");
/// <summary>
/// 记录正常的消息
/// </summary>
/// <param name="msg">消息内容</param>
public static void info(string msg)
{
logInfo.Info(msg);
}
/// <summary>
/// 记录异常信息
/// </summary>
/// <param name="msg">异常信息内容</param>
public static void error(string msg)
{
StackTrace stackTrace = new StackTrace();
StackFrame stackFrame = stackTrace.GetFrame(1);
MethodBase methodBase = stackFrame.GetMethod();
logErr.Error("类名:" + methodBase.ReflectedType.Name + " 方法名:" + methodBase.Name + " 信息:" + msg);
}
}
}
log4net.config
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<!--根配置-->
<root>
<!--日志级别:可选值: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
<!--OFF: 0-->
<!--FATAL: FATAL-->
<!--ERROR: ERROR、FATAL-->
<!--WARN: WARN、ERROR、FATAL-->
<!--INFO: INFO、WARN、ERROR、FATAL-->
<!--DEBUG: DEBUG、INFO、WARN、ERROR、FATAL-->
<!--ALL: DEBUG、INFO、WARN、ERROR、FATAL-->
<level value="DEBUG"/>
<appender-ref ref="ErrorLog" />
<appender-ref ref="WarnLog" />
<appender-ref ref="InfoLog" />
<appender-ref ref="DebugLog" />
</root>
<!-- 错误 Error.log-->
<appender name="ErrorLog" type="log4net.Appender.RollingFileAppender">
<!--目录路径,可以是相对路径或绝对路径-->
<param name="File" value="./logs/error/"/>
<param name="Encoding" value="utf-8" />
<!--文件名,按日期生成文件夹-->
<param name="DatePattern" value="yyyyMMdd'.txt'"/>
<!--追加到文件-->
<appendToFile value="true"/>
<!--创建日志文件的方式,可选值:Date[日期],文件大小[Size],混合[Composite]-->
<rollingStyle value="Composite"/>
<!--写到一个文件-->
<staticLogFileName value="false"/>
<!--单个文件大小。单位:KB|MB|GB-->
<maximumFileSize value="900MB"/>
<!--最多保留的文件数,设为"-1"则不限-->
<maxSizeRollBackups value="15"/>
<!--日志格式-->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%d{HH:mm:ss}][%thread][%logger] - %m%n"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ERROR" />
<param name="LevelMax" value="ERROR" />
</filter>
</appender>
<!-- 警告 Warn.log-->
<appender name="WarnLog" type="log4net.Appender.RollingFileAppender">
<!--目录路径,可以是相对路径或绝对路径-->
<param name="File" value="./logs/warn/"/>
<!--文件名,按日期生成文件夹-->
<param name="DatePattern" value="yyyyMMdd'.txt'"/>
<param name="Encoding" value="utf-8" />
<!--追加到文件-->
<appendToFile value="true"/>
<!--创建日志文件的方式,可选值:Date[日期],文件大小[Size],混合[Composite]-->
<rollingStyle value="Composite"/>
<!--写到一个文件-->
<staticLogFileName value="false"/>
<!--单个文件大小。单位:KB|MB|GB-->
<maximumFileSize value="900MB"/>
<!--最多保留的文件数,设为"-1"则不限-->
<maxSizeRollBackups value="15"/>
<!--日志格式-->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%d{HH:mm:ss}][%thread][%logger] - %m%n"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="WARN" />
<param name="LevelMax" value="WARN" />
</filter>
</appender>
<!-- 信息 Info.log-->
<appender name="InfoLog" type="log4net.Appender.RollingFileAppender">
<!--目录路径,可以是相对路径或绝对路径-->
<param name="File" value="./logs/info/"/>
<!--文件名,按日期生成文件夹-->
<param name="DatePattern" value="yyyyMMdd'.txt'"/>
<param name="Encoding" value="utf-8" />
<!--追加到文件-->
<appendToFile value="true"/>
<!--创建日志文件的方式,可选值:Date[日期],文件大小[Size],混合[Composite]-->
<rollingStyle value="Composite"/>
<!--写到一个文件-->
<staticLogFileName value="false"/>
<!--单个文件大小。单位:KB|MB|GB-->
<maximumFileSize value="900MB"/>
<!--最多保留的文件数,设为"-1"则不限-->
<maxSizeRollBackups value="15"/>
<!--日志格式-->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%d{HH:mm:ss}][%thread][%logger] - %m%n"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="INFO" />
</filter>
</appender>
<!-- 调试 Debug.log-->
<appender name="DebugLog" type="log4net.Appender.RollingFileAppender">
<!--目录路径,可以是相对路径或绝对路径-->
<param name="File" value="./logs/debug/"/>
<!--文件名,按日期生成文件夹-->
<param name="DatePattern" value="yyyyMMdd'.txt'"/>
<param name="Encoding" value="utf-8" />
<!--追加到文件-->
<appendToFile value="true"/>
<!--创建日志文件的方式,可选值:Date[日期],文件大小[Size],混合[Composite]-->
<rollingStyle value="Composite"/>
<!--写到一个文件-->
<staticLogFileName value="false"/>
<!--单个文件大小。单位:KB|MB|GB-->
<maximumFileSize value="900MB"/>
<!--最多保留的文件数,设为"-1"则不限-->
<maxSizeRollBackups value="15"/>
<!--日志格式-->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%d{HH:mm:ss}][%thread][%logger] - %m%n"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="DEBUG" />
<param name="LevelMax" value="DEBUG" />
</filter>
</appender>
</log4net>
十三 页面继承
1 winform 窗体继承后无法编辑
并非所有控件都支持从基本窗体进行可视化继承。以下控件不支持本演练中描述的场景: WebBrowser、ToolStrip、ToolStripPanel、TableLayoutPanel、FlowLayoutPanel、DataGridView 。继承窗体中的这些控件是无论您使用何种修饰符(私有(private)、 protected 或公共(public)),始终为只读。
2 继承窗体 无法拖动修改控件大小
问题描述:一个窗体集成父窗体,发现无法直接拖动修改的控件,比如修改大小等。
特征:
不禁使父窗体控件,就算新加一个控件也会这样:鼠标放到控件移动手方块上会出现一个“继承的控件”的tooptip,
异常
正常情况
原因:
父窗体设置了WindowState属性为:System.Windows.Forms.FormWindowState.Maximized
;
在父窗体的designer.cs中有这么一句话:this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
;
解决办法:
一、去掉这句话;
二、放在窗体构造函数中,在这句话前面加上判断,如果VS处于设计模式,就返回;
public frmBaseChild()
{
InitializeComponent();
if (CheckDesingModel.IsDesingMode) return;//如果处于设计模式,返回
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
}
CheckDesingModel类:
internal class CheckDesingModel
{
public static bool IsDesingMode
{
get
{
bool ReturnFlag = false;
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
ReturnFlag = true;
else if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv")
ReturnFlag = true;
//if (ReturnFlag)
// Msg.Warning("设计模式");
//else Msg.Warning("非设计模式!");
return ReturnFlag;
}
}
}
十四 类调用主窗体控件
在Form1类下定义静态变量,构造方法中引用这个Form1
class Form1: Form
{
public static Form1 form1;
public Form1()
{
InitializeComponent();
form1 = this;
}
public void Method()
{
}
}
调用该窗体的控件或方法
Form1.form1.Button;
Form1.form1.Method();
十五 用户控件属性集合定义
上面已经说过使用属性集合,是因为自定义的控件中有多相同的对象需要在调用时进行设置。(当然你要说是为了把多个属性放在一起好找也不是不行)
下面用两个例子来说明
例1:控件中用到多个图形对象(前景、背景、标志…)
1、创建一个类用来封装调用控件后添加图片对象时需要设置的属性
public class BsItem : Component
{
private Image _imageItem;
[Description("选中图片"), Category("外观")]
public Image SelectImage { get { return _imageItem; } }
private string _ImageName;
[Description("图片路径"), Category("外观")]
public string ImageName
{
get { return _ImageName; }
set
{
_ImageName = value;
this._imageItem = Image.FromFile(_ImageName);
_ImageName = System.IO.Path.GetFileName(_ImageName);
Name = _ImageName;
}
}
}
2、定义一个图片集合
private List<BsItem> items = new List<BsItem>();
[TypeConverter(typeof(System.ComponentModel.CollectionConverter))]//指定编辑器特性
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]//设定序列化特性
[Category("外观"), Description("图像文件集")]
public List<BsItem> ImageList
{
get { return items; }
}
[Browsable(false)]//不显示Name 属性
public string Name { get; set; }
调用时的效果图
例2:控件中用到多个自定义变量,需要在调用时设置:数据来源、不同状态下显示的内容等属性
属性中包含了BOOL,string,图形,枚举,自定义等多种数据类型
方法与例1相同,这些属性的具体使用代码不赘述,只要在{ get; set; }中编写就OK了
private List<DataAttribute> mDataAttribute = new List<DataAttribute>();
[TypeConverter(typeof(System.ComponentModel.CollectionConverter))]//指定类型装换器
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Category("外观"), Description("图像文件集")]
public List<DataAttribute> MDataAttribut
{
get { return mDataAttribute; }
set { mDataAttribute = value; }
}
public class DataAttribute
{
[Description("变量名称"), Browsable(true)]
public string VariableName { get; set; }
[Description("允许读取变量值"), Browsable(true)]
public bool ReadEnabled { get; set; }
[Description("变量存储区"), Browsable(true)]
public catalogOne CatalogOneName { get; set; }
[Description("全局数据块号,DB1对应用户程序的最小全局DB块"), Browsable(true)]
public catalogTwo CatalogTwoName { get; set; }
[Description("变量为1时显示的图片"), Browsable(true)]
public Image TrueImage { get; set; }
[Description("变量为0时显示的图片"), Browsable(true)]
public Image FalseImaRge { get; set; }
[Description("变量未加载时显示的图片"), Browsable(true)]
public Image NotImage { get; set; }
}
效果图
十六 ScottPlot
https://scottplot.net/
https://scottplot.net/cookbook/5.0/
上位机开发过程中,信号数据是最常遇到的,在采集到信号数据后,如果能更好的展示成了难题。刚好最近接手了一个脑电信号数据的采集的项目,需要实时采集脑电信号并以波形展示出来。经过一番调研,网上有不少开源的图形控件用于波形的展示,比如oxyplot,scottplot,livecharts等,在尝试后发现oxyplot采用MVVM设计,非常符合WPF的开发,Scottplot比较符合Winform的开发,而且接口也比较奇怪,livecharts绘图特别漂亮,但有性能问题,比如绘制大数据点时会特别卡。经过详细调研后决定使用Scottplot来实现,理由下面会说。
我们知道波形图由坐标轴来绘制,需要横坐标和纵坐标,像脑电数据,跟采集频率有关,即横坐标是时间递增的,而Scottplot专门为这种横坐标递增的设计了一种波形:Signal Plot(信号图),信号图具有均匀分布的 Y 点。信号图非常快,可以交互显示数百万个数据点。有许多不同类型的可绘制对象,每种都有不同的用途。在实际使用中,只需要将数据以double的数组传进去就行,再设置频率,即可自动生成相应的波形,这对于需要高频采集数据并展示在坐标轴上是非常方便的。
Scottplot的使用可能与WPF的MVVM模式不太适应,官方也不推荐使用MVVM的方式来实现,就直接在后端加载就行。最终效果如图(8KHz的实时采集波形):
Scatter Plot
:散点图
Signal Plot
:信号图
1 图表Title中文显示问题
https://scottplot.net/cookbook/5.0/Internationalization/AutomaticFontDetection/
使用ScottPlot 5.0.23 WinForms控件进行绘图,当图表的标题为非英文时,会显示空白方框。
FormPlot_TestItemRecord.Plot.Title("测试",30);
通过查阅ScottPlot官网中 CookBook-Internationalization-Automatic Font Detection 模块下的文章,发现只需要使用 Font.Automatic()
方法即可完成多种语言的自动适配。
FormPlot_TestItemRecord.Plot.Title("测试",30);
FormPlot_TestItemRecord.Plot.Font.Automatic();