CChart的开发,可以说和C#毫无关系,一开始也没打算在C#上应用,毕竟C#有官方的MsChart摆在那里。就算是现在,一般有朋友问我CChart能不能用在C#上时,我的回答都是推荐使用MsChart。
这是不是说CChart不能用于C#呢?
当然不是了,不然笨笨写这一课干啥呢?
首先看CChart的发布文件CChart_Vs2010.7z,里面有一个文件夹CSharp。这个文件夹下面,有两个文件,CChartu_EXPORTS.txt和C#文件Chart_CSharp.cs。
CChartu_EXPORTS.txt里面,是CChartu.lib里面所有的导出函数,也就是CChartu.dll提供的所有函数。为什么选择CChartu.lib而不是CChart.lib呢?因为C#默认采用宽字节,我们的CChart也应该用宽字节版。
下面看看CSharp文件夹下的另一个文件Chart_CSharp.cs。这是一个C#源代码,实际上是一个C#调用CChart的框架。
那说到底,C#怎么调用CChart呢?
因为C#并不支持C++的类,所以我们的Chart类接口无法暴露给C#,CChartWnd类的接口也无法暴露给C#。前面讲的多种方法都无法使用。
但是,C#可以通过一定的方式,调用C++的函数,这样就给了我们机会。
记得上一课吗?上一课讲的是CChart的C风格代码,说实话,C风格代码没什么用处,需要使用C语言不支持的命名空间。笨笨讲这个的唯一目的,就是C#。
C风格代码只有函数,并不包含类。这些函数的C++声明位于Classless.h头文件里。不过C#并不需要利用这个文件,但编程时需要查询这个文件。
C#调用C++函数的标准方法是利用Dll文件的导出函数,以Chart_CSharp.cs文件里的一个函数void CreateChart()为例。
[DllImport(@"CChartu.dll", EntryPoint = "?CreateChart@Classless@@YAXXZ", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
protected extern static void CreateChart();
这样C#就可以调用CreateChart()这个函数了!
注意到?CreateChart@Classless@@YAXXZ这个样式,一般我们很难直接写出来。怎么办?简单,笨笨已经在CChartu_EXPORTS.txt文件里面,把所有函数的导出样式都包含了,需要哪个函数,在里面查询就可以啦!
还有一个关键点,是C#的Form窗体,其Handle属性,就是一个HWND句柄,有了HWND句柄,CChart就有绘图的对象了,不然我们该往哪里画呢?
到这里为止,所有与C#相关的知识点都已经介绍完了。CChart编程需要提供一个HWND句柄,大家已经知道在那里了;大家都会C风格代码编程;大家又都会导出C风格的函数给C#用,这样C#编程完全没有问题了。
由于利用Dll导出C#函数工作量比较大,在Chart_CSharp.cs文件里,笨笨已经导出了一些最常用的函数,已经可以满足最基本的编程需求。
在这个文件里,笨笨简单组织了一下,形成了几个C#的类,如图所示。
其中,ChartAncestor专门用于导入CChart的函数。ChartBase继承于ChartAncestor,但是其它所有类的父类。MultiChartBase继承于ChartBase,是多视图类的父类。
下面就利用笨笨提供的这个类,在C#实现波形图的绘制。
第一步,建立一个C#的Windows窗体应用程序LessonA22。
结果如图。
第二步,把Chart_CSharp.cs文件拷贝到内层的LessonA22文件夹里,并把它添加到项目里面。同时把Chartu.dll文件拷贝到bin/Debug文件夹里。
第三步,右键点击左侧的Form1.cs,选择“查看代码”,在文件开始位置添加。
using Chart_CSharp;
第四步,在public partial class Form1 : Form的大括号里面,添加XYChart变量。
XYChart chart;
第五步,通过Form1的属性对话框,添加Load行为。
private void Form1_Load(object sender, EventArgs e)
{
chart = new XYChart(this.Handle);
int nLen = 360;
double[] pX = new double[nLen];
double[] pY = new double[nLen];
int i, j;
Random rand = new Random();
for (j = 19; j >= 0; j--)
{
for (i = 0; i < nLen; i++)
{
pX[i] = i;
pY[i] = Math.Sin(i * 2.0 * 3.1415926536 / nLen * 5) / (1.0 + i * 4.0 / 359.0) / (j + 1.0) + (2.0 * rand.Next(100000) / 100000 - 1.0) * 0.04 / (j + 1.0);
if (pY[i] < 0.0) pY[i] = -pY[i];
}
chart.AddCurve(pX, pY, nLen);
}
chart.SetTitle("测试C#曲线图");
}
注意这里的this.Handle,这是一个关键点哟。
第六步,通过Form1的属性对话框,添加布局操作Resize。
private void Form1_Resize(object sender, EventArgs e)
{
chart.ReDraw();
}
大功告成!效果如图。
CChart在C#下的使用还是很简单的,主要的工作量在于CChart函数的导出,不过笨笨已经把最常用的函数处理好了。如果还不能满足需求,按照本节课介绍的方法,把需要用到的函数再导出来就可以啦。