1.引言

由于工作原因,需要对数据进行图表展示,.NET默认的控件库或者DotNetBar的控件库又不能满足需求。去网上找到了这个开源的ZedGraph绘制2D图表的程序集,之所以选择这个ZedGraph程序集,一来它能够满足业务需求,二来它网上相关资料很多,三来它是开源代码。本篇中主要是给大家介绍几个我在开发过程中遇到的一些稍微棘手的问题,或者说是在网上资源较少的问题。在面对这些问题时,对于刚刚接触这个*.dll的我来说还是花了一些时间的,故而总结成篇。

2.相关资料

1.C# WinForm开发系列 - ZedGraph 
2.ZedGraph使用经验 
3.ZedGraph属性\方法介绍

相信认真参研上面的几篇博文,尤其是第一个之后,你对ZedGraph的入门使用会了解许多。如果你想更多的了解ZedGraph,可以Down下源码,仔细研究。ZedGraph的相对来说还是比较简单的,虽然说界面不甚美观,但其功能还算完善,我是做GIS二次开发的,它的几个基本功能:图表漫游、放大、缩小、上一视图等与GIS软件不谋而合。

3.ZedGraph节点Symbol问题

ZedGraph中有个枚举列举了节点的所有常见Symbol(如下),但是有些时候特殊问题特殊处理,我们需要用不同的symbol来表示节点,怎么办?
public enum SymbolType
{
Square,
Diamond,
Triangle,
Circle,
XCross,
Plus,
Star,
TriangleDown,
HDash,
VDash,
UserDefined,//用户自定义
Default,
None
}

参考如下Demo:ZedGraph自定义图标

4.ZedGraph上下文菜单问题

在开发过程中,如果需要实现图表的上下文菜单,需要将ZedGraphControl的IsShowContextMenu属性设置为true才可显示,当然你也可以实现自己的自定义上下文菜单。这里需要注意的是,有些你下载的dll可能上下菜单是中文,而有些却是英文并且有可能"缺损"了那么几项,造成这个问题的主要是由于ZedGraph开源,网友很有可能是改完源码之后上传的,这就造成你Down下来的dll不尽相同。现在的问题是:怎么修改ZedGraph的上下文菜单,英文<->中文?隐藏某一选项?代码如下:
private void zGCDateChart_ContextMenuBuilder(ZedGraphControl sender, ContextMenuStrip menuStrip, Point mousePt, ZedGraphControl.ContextMenuObjectState objState)
{
try
{
//每次循环只能遍历一个键
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "copy")
{
item.Text = "复制";
item.Visible = true;
break;
}
}
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "save_as")
{
item.Text = "另存图表";
item.Visible = true;
break;
}
} foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "show_val")
{
item.Text = "显示XY值";
item.Visible = true;
break;
}
}
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "unzoom")
{
item.Text = "上一视图";
item.Visible = true;
break;
}
}
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "undo_all")
{
item.Text = "还原缩放/移动";
item.Visible = true;
break;
}
}
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "print")
{
menuStrip.Items.Remove(item);
item.Visible = false; //不显示
break;
}
}
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "page_setup")
{
menuStrip.Items.Remove(item);//移除菜单项
item.Visible = false; //不显示
break;
}
}
foreach (ToolStripMenuItem item in menuStrip.Items)
{
if ((string)item.Tag == "set_default")
{
menuStrip.Items.Remove(item);//移除菜单项
item.Visible = false; //不显示
break;
}
} }
catch (System.Exception ex)
{
MessageBox.Show("初始化右键菜单错误" + ex.ToString());
}
}

这里需要注意几点:
1.事件为ContextMenuBuilder
2.每次foreach循环只能遍历一个键,因为你改变了枚举项。

5.添加文本问题

有些时候需要你在图表是添加一些文本,比如说:

TextObj text_obs = new TextObj("缩放:鼠标滚轮\n移动:鼠标中键\n菜单:鼠标右键", 0.899f, 0.001f, CoordType.ChartFraction, AlignH.Center, AlignV.Bottom);
text_obs.FontSpec.StringAlignment = StringAlignment.Center;
text_obs.FontSpec.Fill = new Fill(Color.LightBlue);
text_obs.FontSpec.FontColor = Color.Black;
myPane_obs.GraphObjList.Add(text_obs);

double xVal = Math.Round(list[i].X, 2);
double yVal = Math.Round(list[i].Y, 2);
string lab = string.Format("高潮位\r\n时间:{0}\r\n潮位:{1}", GetStrTime(xVal), yVal);
TextObj text = new TextObj(lab, (float)xVal, (float)yVal * 1.01);//设置一个偏移量
text.FontSpec.StringAlignment = StringAlignment.Near;
text.Location.CoordinateFrame = CoordType.AxisXYScale;//很重要,设置参考系,或者说参考坐标
text.FontSpec.Size = 10;
text.FontSpec.FontColor = Color.Blue;
text.Location.AlignH = AlignH.Center;
text.Location.AlignV = AlignV.Bottom;
text.FontSpec.Border.IsVisible = false;
text.FontSpec.Angle = 0;
text.FontSpec.Fill.IsVisible = false; myPane.GraphObjList.Add(text);

6.节点显示悬停提示和悬停提示闪烁问题

当你需要鼠标悬停在图表节点上提示节点的位置值,或者其他的一些内容时,你需要首先将ZedGraphControl的IsShowPointValues属性设置为true,然后关联事件PointValueEvent。
private string zGCDateChart_PointValueEvent(ZedGraphControl sender, GraphPane pane, CurveItem curve, int iPt)
{
PointPair pt = curve[iPt];
return "时间:" + pt.X.ToString() + " \n潮位:" + pt.Y.ToString();
}
如果这样就把问题解决了,那固然好,可我在做的过程中发现的一个问题,或者说是不尽如人意的地方:当鼠标悬停在节点上时,内容是显示出来了,没有问题,但是悬停提示框就是一直在闪烁,这个问题困扰了我很久,解决方法如下:

找来ZedGraph的源码,在ZedGraphControl.Event.cs中找到了下面这块代码:
private Point HandlePointValues( Point mousePt )
{
int iPt;
GraphPane pane; object nearestObj;
using ( Graphics g = this.CreateGraphics() )
{
if ( _masterPane.FindNearestPaneObject( mousePt,g, out pane, out nearestObj, out iPt ) )
{
if ( nearestObj is CurveItem && iPt >= 0 )
{
//................ //code to show the tooltip
}
else
this.pointToolTip.Active = false;
}
else
this.pointToolTip.Active = false;
}
return mousePt;
}
分析后发现,原来这段代码不论鼠标移动的范围大小,甚至乎不论鼠标是否移动,都要刷新一次Tooltip,所以才会导致CPU爆满。

解决方案并不复杂,包括三个步骤:
1、创建私有变量lastObj用以保存上次为之显示Tooltip的对象;
2、显示Tooltip前判断对象是否就是lastObj;
3、将新获得的对象保存到lastObj中。
修改后的代码结构如下:
private object lastObj;
private Point HandlePointValues( Point mousePt )
{
int iPt;
GraphPane pane; object nearestObj;
using ( Graphics g = this.CreateGraphics() )
{
if ( _masterPane.FindNearestPaneObject( mousePtg, out pane, out nearestObj, out iPt ) )
{
if (nearestObj is CurveItem && iPt >= 0 && !object.Equals(nearestObj, lastObj))
{
//................ //code to show the tooltip
}
//else
// this.pointToolTip.Active = false;
}
else
this.pointToolTip.Active = false;
}
lastObj = nearestObj;
return mousePt;
}

7.X轴刻度重写(X轴刻度循环问题)

简单的X、Y轴刻度刻度形式可以通过设置以下属性来实现:
myPane_obs.XAxis.Scale.Format = "";
myPane_obs.YAxis.Scale.Format = "";

本次开发中碰到的是关于X轴循环问题,X轴是一根绝对的数轴,但是现实的数值代表时间,并且时间从0—23时不断重复循环,也就是说不会出现负数和大于23的整数,具体解决方案如下:

myPane_obs.XAxis.Scale.Min = 0;
myPane_obs.XAxis.Scale.Max = 24;
myPane_obs.XAxis.Scale.MajorStep = 4;
myPane_obs.XAxis.Scale.MinorStep = 1;
/// <summary>
/// X轴刻度重定义
/// </summary>
/// <param name="pane"></param>
/// <param name="axis"></param>
/// <param name="val"></param>
/// <param name="index"></param>
/// <returns></returns>
string XAxis_ScaleFormatEvent(GraphPane pane, Axis axis, double val, int index)
{
if (val >= 0 && val < 24)
return val.ToString();
else if (val >= 24)
return (val % 24).ToString();
else
return (24-Math.Abs(val % 24)).ToString();
}

关于ZedGraph几个难点的更多相关文章

  1. C#图表控件ZedGraph使用

    最近从java转到C#下开发PC端的桌面程序,之前也尝试用java GUI写桌面程序,发现java写桌面程序还是诸多不便变,虽然最后也写出来了,但是决心还是另起平台,有了一定的java基础,来学习C# ...

  2. 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇二:基于OneNote难点突破和批量识别

    篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...

  3. Android开发重点难点1:RelativeLayout(相对布局)详解

    前言 啦啦啦~博主又推出了一个新的系列啦~ 之前的Android开发系列主要以完成实验的过程为主,经常会综合许多知识来写,所以难免会有知识点的交杂,给人一种混乱的感觉. 所以博主推出“重点难点”系列, ...

  4. Unity 难点目录

    1.mesh的任意切割.(难点) 2.扇形区域识别玩家.(解决) 3.NGUI横滑同时竖滑,或滑动同时点击冲突处理.(解决)

  5. 新浪微博SDK开发(2):上传图片的技术难点

    在微博模块中,有一个API是可以发表带一张图片的微博的,当然提交方式是POST.在封装的时候,可能会遇到一个难点——如何上传图片? 要POST微博的同时带有图片,POST的内容必须为MultiPart ...

  6. C# ZedGraph 控件各属性以及示例

    ZedGraph属性\方法介绍 Copy(Boolean) ->> 将图像复制到剪贴板.DoPageSetup()() ->> 打开打印设置对话框. DoPrint()() - ...

  7. .NET_RSA加密全接触(重、难点解析)

    .NET_RSA加密全接触(重.难点解析) .NET Framework提供了两个类供我们使用RSA算法,分别是:用于加密数据的RSACryptoServiceProvider和用于数字签名的DSAC ...

  8. js 函数闭包内部返回函数体调用方法难点解答

    今天在网上,看到一篇关于js函数难点的文章,js函数的一些难点.在那上面提了一下,关于js函数返回另一个函数的问题,并附上了一道面试题: var add = function(x){ var sum ...

  9. C# WinForm开发系列 - ZedGraph

    ZedGraph是用于创建任意数据的二维线型.条型.饼型图表的一个类库,也可以作为Windows窗体用户控件和Asp.Net网页控件.这个类库具有高度的适应性,几乎所有式样的图表都能够被创建.这个类库 ...

随机推荐

  1. Android音频播放之SoundPool 详解

    SoundPool —— 适合短促且对反应速度比较高的情况(游戏音效或按键声等) 下面介绍SoundPool的创建过程: 1. 创建一个SoundPool (构造函数) public SoundPoo ...

  2. Bitbox : a small open, DIY 32 bit VGA console

    Bitbox : a small open, DIY 32 bit VGA console Hi all, I've been developing a simple DIY console and ...

  3. LPC-Link-II Rev C JTAG

  4. Delphi如何在Form的标题栏绘制自定义文字

    Delphi中Form窗体的标题被设计成绘制在系统菜单的旁边,如果你想要在标题栏绘制自定义文本又不想改变Caption属性,你需要处理特定的Windows消息:WM_NCPAINT.. WM_NCPA ...

  5. 基于设备树的TQ2440 DMA学习(1)—— 芯片手册

    作者 彭东林pengdonglin137@163.com 平台 TQ2440内核Linux4.9 概述 一直想抽时间学习一下DMA驱动,今天就以S3C2440为例,这款芯片的DMA控制器足够简单,也比 ...

  6. 使用Axure RP原型设计实践06,登录验证

    登录验证主要功能包括: ● 用户名错误,提示无效用户名,用户名和密码文本框清空● 用户名存在,密码错误,提示密码错误,密码清空,焦点进入密码框● 用户名和密码都正确,验证通过 本篇接着"使用 ...

  7. C#输出到Release VS中Release模式下生成去掉生成pdb文件

    Release 与 Debug 的区别就不多说了, 简单来说 Release 优化过, 性能高一些. Debug 为方便调试. 默认情况下是 Debug, 那如何改成 Release 呢? 项目上右键 ...

  8. 【java】ThreadLocal线程变量的实现原理和使用场景

    一.ThreadLocal线程变量的实现原理 1.ThreadLocal核心方法有这个几个 get().set(value).remove() 2.实现原理 ThreadLocal在每个线程都会创建一 ...

  9. 【spring boot】spring boot 前台GET请求,传递时间类型的字符串,后台无法解析,报错:Failed to convert from type [java.lang.String] to type [java.util.Date]

    spring boot 前台GET请求,传递时间类型的字符串,后台无法解析,报错:Failed to convert from type [java.lang.String] to type [jav ...

  10. java单例模式实例

    什么是单例模式? 定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例场景,也就是说:确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象应该有且只有一 ...