开发GIS应用简明教程

关于C#开发GIS应用简明教程的说明
Web上的GIS,我个人觉得C#+MAPX并不是一个好的解决办法,因为有许多的GIS工具更适合于WEB环境和C#语言,只是我自己在这方面也没什么研究。所以只能对大家说抱歉了。
第一章   准备
使用C#开发GIS应用,你应该首先在系统中安装Visual Studio .Net(建议使用2003版本),然后还需要安装MapInfo公司开发的MapX 5.0版本.MapX

的4.X版本和.Net的兼容有一些问题.可能无法实现本教程介绍的某些功能.
另外,你还应该尽可能地收集所有关于.NET,C#和MapX有关的资料,教程非常实用,专门解决技术问题,而不打算列举资料,所以,最好手头上有一些

备查的资料.如果实在找不到,最起码要求能看懂MSDN.Met和MapX的帮助.
关于.Net的安装很多教程都有涉及,此处不再赘述
MapX 5.0的安装很容易,按照提示一步步就可以安装,和一般的软件安装没什么区别,安装完控件以后千万别忘了同时安装附带的地图数据.
安装好以上软件后,还需要在.Net编程环境中加入MapX 5.0控件.
在.Net编程环境中新建一个WindeosApplication(Windows应用程序)项目,然后在菜单中选择”项目/添加引用”,打开如下图的窗口,在窗口中选

择COM标签,在组件名称列表中双击MapInfo MapX V5.单击"确认"按钮,即可将Map5控件加入到.Net的工具箱中.
现在,所有的准备工作都已经完成了,为了测试安装是否正确,我们做个简单的地图放大程序.
在刚刚打开的项目中,从工具栏中选择Mapinfo MapX V5控件,把它画到项目中的Form1窗口上,如下图:
增加一个Button控件button1,将它的Text属性改为”放大”,如下图:
在设计窗口中双击按钮并编写代码如下:
private void button1_Click(object sender, System.EventArgs e)
{
axMap1.CurrentTool=MapXLib.ToolConstants.miZoomInTool;
}
编译,运行程序.如果没有什么错误的话,准备工作就已经完成了.
练习:1.     完成应用程序,在窗口中实现放大,缩小,漫游功能.
2.     熟悉MapInfo MapX中的GeoSet Manager程序.
3.     了解GIS的有关知识.(推荐到"程序员资源大联盟"网站查看相关版块的内容.


第二章入门
 1.工具(ToolConstants)
在上一章里我们试着做了一个将地图放大的应用程序.在这章里,我们将接触到更多的工具,并介绍自定义工具.
MapX为开发人员提供一系列的工具,这些工具的作用各有不同,我们通过开发一个应用程序来了解这些工具的作用,至于这些工具的具体说明,可

以在MapX的帮助文档中,通过查找"Available Standard Tools" 看到相应的解释.一些MapX的相关资料也有介绍.
在.Net编程环境中新建一个C#的WindeosApplication(Windows应用程序)项目,然后在菜单中选择”项目/添加引用”,打开如下图的窗口,在窗口

中选择COM标签,在组件名称列表中双击MapInfo MapX V5.单击"确认"按钮,将Map5控件加入到.Net的工具箱中.
接着,将MapInfo MapX V5 控件画到窗体上,再在窗体上画一个ComboBox控件comboBox1.如下图:
双击设计窗体,编写Form1_Load代码如下:
private void Form1_Load(object sender, System.EventArgs e)
{
    ArrayList ToolsList=new ArrayList();
    ToolsList.Add(MapXLib.ToolConstants.miArrowTool);
    ToolsList.Add(MapXLib.ToolConstants.miCenterTool);
    ToolsList.Add(MapXLib.ToolConstants.miLabelTool);
    ToolsList.Add(MapXLib.ToolConstants.miPanTool);
    ToolsList.Add(MapXLib.ToolConstants.miPolygonSelectTool);
    ToolsList.Add(MapXLib.ToolConstants.miRadiusSelectTool);
    ToolsList.Add(MapXLib.ToolConstants.miSymbolTool);
    ToolsList.Add(MapXLib.ToolConstants.miTextTool);
    ToolsList.Add(MapXLib.ToolConstants.miZoomInTool);
    ToolsList.Add(MapXLib.ToolConstants.miZoomOutTool);
    comboBox1.DataSource=ToolsList;
}
以上代码通过一个数组ToolsList,将MapXLib的工具加入到comboBox1中.MapX还有一些其它的工具,它们的作用是往地图上加上点,线,多边型和

圆.因为这些工具要求有操作图层,一并在介绍图层的时候介绍.关于ArrayList的用法,请参考C#的有关资料.
接着,双击comboBox1,并编写代码如下
private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
axMap1.CurrentTool=(MapXLib.ToolConstants)comboBox1.SelectedItem;
}
应注意,在C#中必须要显式地把comboBox1的选择项目SelectedItem(数据类型为object)转换为MapXLib.ToolConstants.因为ToolConstants是

MapX自己定义的一个枚举数据类型,C#不能自动完成这种枚举成员变量到object的数据转换.
编译执行程序,从comboBox1中选择不同的工具,在地图上进行操作,你可以了解到MapX工具集的强大功能.
实际上,MapX提供的工具集就好像Photoshop,AutoCAD的工具栏一样,为你提供了一些控制地图的工具.但是,在开发GIS的时候,这些工具是不能完

全满足要求的.所以,还应该学会自定义工具.
下面,通过一个在地图上测距的例子,来介绍一下如何在C#下自定义MapX工具
如前所述建立一个C#的Windows应用程序并将Mapinfo MapX V5 控件加到窗体上.并加入一个Button控件button1.将button1的Text属性改为"测

距",再在窗口中放上两个Label控件label1,label2,将它们的Text属性设置为""空字符串,如下图:
双击设计窗体,编写Form1_Load代码如下:
private void Form1_Load(object sender, System.EventArgs e)
{
axMap1.CreateCustomTool(100,MapXLib.ToolTypeConstants.miToolTypePoly,
MapXLib.CursorConstants.miCrossCursor,null,null,null);
}
在加载窗口的时候,我们定义了一个工具.它的编号是100(不要和MapX本身的工具编号重复),它的类型是一个多义线,采用十字光标.
关于此函数的用法,建议查看MapX的开发手册和相关资料.
现在我们定义了一个编号为100的工具,可以在程序中使用它了.双击设计窗体中的button1,编写它的Click事件处理代码如下:
private void button1_Click(object sender, System.EventArgs e){
axMap1.CurrentTool=(MapXLib.ToolConstants)100;
}
现在编译运行,单击button1,就可以在地图上使用这个工具了.但是还有一部分重要的代码没有完成:测距!
完成测距功能的代码在C#使用MapX开发GIS中非常具有代表性,也比较有难度.我在首次使用C#+MapX开发GIS的时候,被这个问题困扰了很久.项目

经理也来研究,过两天说有结果了,但他给出的例子根本就行不通.当然,会了就不难了.其实,也很简单.
首先,在窗口类中声明两个私有全局变量以保存测出的距离和总距,注意声明代码的位置:
public class Form1 : System.Windows.Forms.Form
{private AxMapXLib.AxMap axMap1;
 private System.Windows.Forms.Button button1;
 private System.Windows.Forms.Label label1;
 private System.Windows.Forms.Label label2;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
private double Dis=0,DisSum=0;
现在来编写工具的事件.注意,在MapX画多义线的时候,它触发消息的方式和一般的工具是不同的,首先,它并不是用鼠标一点击就完成了的,还可

以继续画下去,所以,不应该在MapX控件的ToolUsed事件中编写,而应该在PolyToolUsed事件中实现测距.代码如下:
private void axMap1_PolyToolUsed(object sender, AxMapXLib.CMapXEvents_PolyToolUsedEvent e){  
MapXLib.PointsClass pts=new MapXLib.PointsClass();  
switch(e.flags)
{
case (int)MapXLib.ToolFlagConstants.miToolInProgress:
pts=(MapXLib.PointsClass)e.points;
Dis=axMap1.Distance(pts._Item(pts.Count-1).X,
pts._Item(pts.Count-1).Y,
pts._Item(pts.Count).X,
pts._Item(pts.Count).Y);
DisSum+=Dis;
break;
default:
Dis=0;
DisSum=0;
break;
}
label1.Text="距离:"+Dis.ToString("#.00");
label2.Text="总距"+DisSum.ToString("#.00");
}
 这段代码虽短.但要注意的地方很多.

首先,定义一个MapXLib.PointsClass类型的变量pts,注意,是PointsClass,不是PointClass.前者是点集,后者是点.为什么要增加那么一个变量

呢?因为MapX的PolyToolUsed事件的返回参数e的成员points不是MapXLib.PointsClass类型,而是object.类型.所以需要这么一个变量来转换它,

当然,你也可以在程序使用pts的地方直接使用(MapXLib.PointsClass)e.points,但那样一来程序就比较难懂了;

其次,要判断事件的标识e.flags的值,它指出工具当前的状态,是刚开始画多义线呢,还是正在画多义线,或者已经结束了,或者结束退出.我们只

要在画的时候测距就可以了.其它时候将距离和总距都设置为0;

接着,还要注意的是e.points的点数据保存方式,e.points首先是一个object,当在画多义线的时候,它被初试化为一个MapXLib.PointsClass的变

量,并以二维数组的方式保存点集.这个数组是从1开始的,而不是从0开始的.它保存了多义线上每个转折点的坐标,鼠标每点一下,就增加一个新

的数据到点集,我们计算最后一条直线长度,应该从这个数组的末尾往前取.计算好距离以后再加入到总距中.许多测距的程序例子都要做一个循

环,其实是不必要的.

最后,请注意数字转换到字符串的格式问题.在这个例子中我们保留两位小数.

补充一点,因为没有设置地图的地理坐标系统,所以测出来的距离单位是英里,如果要改为公里,把MapX控件的MapUnit属性改为miUnitKilometer

就可以了.要提高测量精度,除了可以通过转换格式的时候增加小数位,还应该注意到地图的测绘精度.否则,再多的小数位也是没有意义的.
练习

1.建立一个应用程序,加入MapX控件和一个ComboBox控件,两个:Label控件,在ComboBox中加入第一个例子中的所有工具和测距工具,在ComboBox

中选择测距工具时实现测距功能.

2.将测距工具的光标改成箭头光标.并以米为单位显示测距数据.

2.图层和图元(Layers and Features)

有关图层和图元的概念,请参照相关资料.

图层的应用分为几个方面,我们分别加以介绍.

1)图层的创建:

创建永久图层:

在C#中,使用以下方法创建永久图层:

MapXLib.Layer lyr;
lyr=axMap1.Layers.CreateLayer("MyLayer","D:\\MapTest\\MyLayer.Tab",0,32,axMap1.DisplayCoordSys);
当执行这两句程序时,在指定的路径生成了一系列文件.它们是:
MyLayer.Dat:图层的数据文件,它保存的是图层的数据库数据;
MyLayer.ID:图层数据的唯一的,自动生成的编码,用以区分不同的图元;
MyLayer.IND:图层数据的索引文件,以实现图层上图元的快速查找;
MyLaer.MAP:图层上图元的图形数据;
MyLaer.TAB:这是一个文本文件,它的作用是将图层的有关信息保存起来,供GST地图文件或其它程序调用图层.
用记事本打开MyLayer.TAB文件,看到如下内容:
!table
!version 450
!charset WindowsSimpChinese
Definition Table
Description "MyLayer"
Type Native charset "WindowsSimpChinese"
Fields 1
GEONAME char (32) Index 1 ;
第一行总是"!table",说明这是一个图层表的文件;
第二行指出图层文件的版本号,MapInfo MapX 5.0生成的图层版本号是450;
第三行指出生成图层的操作系统;
接着是对图层的定义段:
首先指出图层的描述,就是我们上面程序代码中的"Mylayer".
接着说明了字符集类型是简体中文;
然后指出表格中只有一个字段,这个字段的名称是"GEONAME",是长度为32的字符类型字段,在表中的列索引为1.
2)添加现有的图层:
添加现有图层的方法和一般的程序语言没有很大的区别,我们在当前图层上添加刚才创建的永久图层,程序代码如下:
MapXLib.LayerInfo li;
li=new MapXLib.LayerInfoClass();
li.Type=MapXLib.LayerInfoTypeConstants.miLayerInfoTypeTab;
li.AddParameter("FileSpec","D:\\MapTest\\MyLayer.tab");
li.AddParameter("Visible",false);
li.AddParameter("AutoCreateDataset",true);
li.AddParameter("DatasetName","MyLayer");
axMap1.Layers.Add(li,0);
axMap1.Layers.LayersDlg("","");
axMap1.SaveMapAsGeoset("测试","D:\\MapTest\\MyMap.GST");
在程序的最后,我们显示了图层信息对话框,以观察图层是否已经添加到当前的地图中.可以看到,地图中添加了我们创建的图层"MyLayer".放在

第0层.
然后,将地图保存在一个MyMap.GST的地图文件中,这个地图的标题是"测试".
3)移除图层:
好,接着我们上面做的工作,将工程的axMap1的GeoSet属性设置为刚刚生成的地图文件: "D:\MapTest\MyMap.GST".现在我们将MyLayer从地图中

移除.
添加一个按钮,在按钮的Click事件中编写如下代码:
axMap1.Layers.LayersDlg("","");
axMap1.Layers.Remove(1);
axMap1.Layers.LayersDlg("","");
我们使用两次显示图层对话框的方式查看程序的效果,应该注意的是在Remove第0层的时候使用的是Remove(1),如果不清楚图层的位置,就要作一

个循环,将图层的位置取出来再移除,如下:
int lyrind=0;
axMap1.Layers.LayersDlg("","");
for( int i=1;i<axMap1.Layers.Count;i++)
{
 if (axMap1.Layers[i]._Name.Trim()=="MyLayer")
    {
       lyrind=i;
       break;
    }
}
axMap1.Layers.Remove(lyrind);
axMap1.Layers.LayersDlg("","");
移除操作只在内存中进行,也就是说,程序并不删除任何文件,也没有将图层真正地从地图集合中去掉,当程序重新启动的时候,MyLayer图层仍然

在地图中.
3)移除所有图层:
使用axMap1.Layers.RemoveAll();就可以移除所有图层,用法和Remove相似.
4)图层定位:
和其它编程语言一样,使用axMap1.Move(1,2)函数就可以将图层的位置改变.
5)创建临时图层
临时图层和永久图层不同,它只存放在内存中,当关闭程序以后该图层将不存在.
在这里我们将使用LayerInfo对象来创建临时图层,这和传统的MAPX程序相近,但是引入了C#编程的一些特色:
MapXLib.LayerInfoClass li=new MapXLib.LayerInfoClass();
MapXLib.Features ftrs=null;
MapXLib.FieldsClass flds=new MapXLib.FieldsClass();
MapXLib.Fields Myflds=null;
MapXLib.Dataset dts=null;
flds.Add("State","State_Name",
MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeString);
dts=axMap1.DataSets.Add(MapXLib.DatasetTypeConstants.miDataSetLayer,
axMap1.Layers._Item(1),"MyLayer",0,0,0,flds,false);
Myflds=dts.Fields;
ftrs=axMap1.Layers._Item("USA").Selection.Clone();
li.Type=MapXLib.LayerInfoTypeConstants.miLayerInfoTypeTemp;
li.AddParameter("Name","USA Temp Layer");
li.AddParameter("Fields",Myflds);
li.AddParameter("Features",ftrs);
axMap1.Layers.Add(li,1);
axMap1.Layers.LayersDlg("","");
这段程序有两个关键的地方:
一个是在C#中DataSets.Add的用法,在许多编程语言中,都可以使用空的参数或者干脆不用参数来调用这个函数,但是在C#中是不行的,必须8个参

数全部指定.而且,还应该事先初始化Fields参数.这个函数的使用涉及到许多方面的知识,包括对MAPX相关概念的理解和C#编程的认识,是一个很

重要,也比较难掌握的技术.后面的章节中我们还会作进一步的探讨.
另一个是li.AddParameter和li.Type的配合使用问题,这在许多的MAPX书籍中都有论述,此处不再重复.
以上程序最好能自己多琢磨琢磨.才能更好地掌握C#开发GIS的要领.
6)缩放图层:
所谓的缩放图层,并不是指将单个图层缩放.而是指定图层的可见范围比例,例如,设置一个图层在缩小显示大于5英里的时候隐藏.小于5英里的时

候显示.和其它编程语言一样,只要设置Layer的ZoomMin和ZoomMax就可以了.
7)显示整个图层:
这里要提及的一个技巧是在C#下面怎样显示整个图层.众所周知,在VB下面只要:
Map1.Bounds = Map1.Layers("USA").Bounds
一句程序就可以轻松实现.但是要是在C#中这样写的话,百分百会出错.其实,这里有一个小小的技巧,聪明的你一定能看出来:
axMap1.CtlBounds=axMap1.Layers._Item("USA").Bounds;
8)在图层上绘制永久图形:
我们在介绍工具的时候,有一些工具没有介绍,这些工具其实是用来在图层上创建永久图形对象的(图元).当在图层上绘制了图形以后,这些图形

将以数据记录的形式保存在图层表中,也就是创建了一个图元.如果不想保存图元,可以在临时图层里绘制.
axMap1.Layers._Item("USA Temp Layer").Editable=true;
axMap1.Layers.InsertionLayer=axMap1.Layers._Item("USA Temp Layer");
axMap1.CurrentTool=MapXLib.ToolConstants.miAddLineTool;
上面的程序使用了画线的工具,在地图上拖动鼠标就可以在临时图层上画线了.这些工具使用的前提是必须指定axMap1的插入图层

(InsertionLayer).才能在图层表中插入数据.
关于图层的关键技术就介绍到这里,掌握了这些技术以后,在作进一步的研究时,例如动画图层和绘制图层的开发,遇到的困难应该不大.
下面我们介绍C#对MAPX图元的编程技术.
9)在图层上创建图元:
根据MAP Info提供的MapX 5.0开发手册,创建图元有两种方法,用两段代码说明这两种代码在C#的实现方法:
第一种实现方法:直接使用Feature类创建图元
MapXLib.Style sty=new MapXLib.StyleClass();
MapXLib.Feature ftr=new MapXLib.FeatureClass();
ftr.Attach(axMap1.GetOcx());
ftr.Type=MapXLib.FeatureTypeConstants.miFeatureTypeText;
sty.TextFontColor=255;
sty.TextFont.Size=12;
ftr.Style=sty;
ftr.Caption="New Feature";
ftr.Point.Set(axMap1.CenterX,axMap1.CenterY);
axMap1.Layers._Item("US Top 20 Cities").Style=sty;
ftr=axMap1.Layers._Item("US Top 20 Cities").AddFeature(ftr,new MapXLib.RowValuesClass());
ftr.Update(ftr,new MapXLib.RowValuesClass());
有几个要注意的地方:
ftr.Attach(axMap1.GetOcx());
如果在VB6下,这句程序应该是这样的:
ftr.Attach Map1
从这里可以看到在C#中因为严格的类型管理所带来的一些变化.如果不进行GetOcx()的转换,即使在VB.Net下也是错误的.
ftr=axMap1.Layers._Item("US Top 20 Cities").AddFeature(ftr,new MapXLib.RowValuesClass());
我们在这个程序中加入了一行空的数据,这也就代表着我们加入的图元不包含任何数据信息.这是为了在介绍图元的时候方便大家掌握,并不意味

着这样增加图元就不能将数据保存进去,实际上,通过设置一个新的RowValues变量,是可以将数据信息保存到图元中的.我们将在后面的章节中介

绍如何将数据保存在图元中.
ftr.Update(ftr,new MapXLib.RowValuesClass());
这句程序的作用是将创建的图元保存到图层表中,这种保存是永久保存的.除非是在临时图层上增加的图元,否则下次打开地图文件的时候,将看

到创建的图元仍然保留在地图上.因此,在对图元操作之前请备份好地图文件,避免不必要的损失.
另外,关于图元的类型(Type)和风格(Style),应该和其所在的图层相对应,比如上面程序中关于Type和Style的设置,都是和"US Top 20 Cities"

图层的类型对应的.有关类型和风格的设置,请查阅相关手册.
第二种实现方法:使用FeatureFactory创建图元
MapXLib.Feature ftr=new MapXLib.FeatureClass();
MapXLib.Point p=new MapXLib.PointClass();
p.Set(axMap1.CenterX,axMap1.CenterY);
ftr=axMap1.Layers._Item("US Top 20 Cities").AddFeature(axMap1.FeatureFactory.CreateText
(p,"New Feature",MapXLib.PositionConstants.miPositionCC,
new MapXLib.StyleClass()),
new MapXLib.RowValuesClass());
这段代码和上面和第一种实现方法类似,我们在这里不再设置图元的Type和Style.
FeatureFactory类似于设计模式中的Factory模式,从它可以产生各种类型的图元,这个过程相当于设置了图元的Type.
10)查找图元:
查找图元是很简单的,可以用下边的代码实现:
MapXLib.FindFeature fRes=null;
fRes=axMap1.Layers._Item("US Top 20 Cities").Find.Search("New York","");
axMap1.CenterX=fRes.CenterX;
axMap1.CenterY=fRes.CenterY;
上面这段代码将找到的图元放置在地图中央.这里要注意的是不能使用
MapXLib.FindFeature fRes=new MapXLib.FindFeatureClass();
来创建FindFeature对象,否则将会出错:
"带有 CLSID {436052C3-43E3-11D0-83EB-00AA00BD34FC}的COM对象无效或未注册。"这是MapX 5.0的一个Bug.要避开它,只要在创建对象的时候

赋null值就可以了.
下面我们对程序作一些改进,来避免找不到图元的时候出错,并在找到图元以后选择该图元:
MapXLib.FindFeature fRes=null;
fRes=axMap1.Layers._Item("US Top 20 Cities").Find.Search("New York","");
if (fRes.FindRC % 10 ==1)
{
    axMap1.CenterX=fRes.CenterX;
    axMap1.CenterY=fRes.CenterY;
    axMap1.Layers._Item("US Top 20 Cities").Selection.Add(fRes);
}
11)图元的修改:
图元的增加,修改和删除都是非事务性的,也就是说,所作的修改都永久性地对图层表数据产生影响.这可以使用户对多个图元进行操作后一次更

新地图,但是在更新之前并不能看到更新后的效果.我们在使用第一种方法创建图元的时候,在最后更新:
ftr.Update(ftr,new MapXLib.RowValuesClass());
但是在FeatureFacory创建图元的时候是不用Update的,因为FeatureFactory的相关方法中已经包含了Update.根据MapX 5.0的开发手册介绍,修

改了某个图元并更新时应使用Feature.Update方法,当使用其它图元取代某个图元,应使用Layers.UpdateFeature方法.
12)图元的删除:

和其它编程语言一样,删除图元使用DeleteFeature方法,有关介绍请参看MapX的联机帮助和开发手册.

练习:

1.结合以上例子,并参考相关资料,在地图上建立一个临时图层,并在该图层上加入图标类型(.bmp文件)的图元.
2.自定义一个工具,使用该工具删除图元.
注意: 在对图元操作之前请备份好地图文件,避免不必要的损失.

第三章数据处理

在介绍数据处理之前,我们先在MapInfo中生成自己的地图,在本章中将全部使用自己生成的地图.这是因为MapX本身提供的地图和实际应用的地

图在数据结构上有较大的差异.不适合用来介绍MapX的数据处理.
首先安装好MapInfo,最好能使用7.0以上的版本.以下操作在MapInfo Professional 7.0版本下完成.
打开MapInfo,界面如下图:
单击工具栏最左边的  按钮,新建一个图层数据表.如下图在"New Table"窗口中按照上图选择后单击"Create..."按钮,建立一个新的数据图

层.MapInfo会弹出一个窗口,如下图:
在这个窗口中设置好数据表的字段属性.单击"Add Field"按钮将字段添加到表中,我们在这里将添加4个字段:ID,名称,月供年限和水电费.设置

好的字段如下图:
设置好以后,单击"Create..."按钮,MapInfo将询问建立图层表的文件路径.将你的图层表文件名改为"HouseLayer.Tab",存放到合适的路径下.例

如:" E:\Test\DataMap\".
保存完毕以后,得到一个空白的图层表文件,MapInfo打开了这个文件显示如下:
这个图层表上现在还没有任何图形,我们在图层上增加两个图元,并把数据添加上去.
在Drawing工具条上选择画矩形的工具,在HouseLayer Map上画一个矩形,然后使用拷贝粘贴的功能将其复制为另一个矩形.
选择图元后,对两个图元稍做修饰.如下图:
现在,简单的作图就完成了.
接着输入和图形相关的数据.选择如下图指示的按钮,在图层上点选图元,打开输入数据的窗口.
在输入数据的窗口中输入以下两条数据:
ID    名称 月供年限 水电费

0001  A栋   25        18.77
0002  B栋   30        25.12
保存图层.MapInfo的画图工作就完成了.
你还需要在MapX 5.0自带的工具Geoset Manager里把刚刚画好的图层放到一个地图文件(.GST格式)里,才能被MapX调用,我们把这个文件命名为"

小区.GST".
 好,准备工作就绪,现在我们开始介绍MapX的数据处理.
1.数据读取 (Data Reading)
先对程序的功能作一些说明:把小区地图放在MapX控件上,并且在窗口的左边放置一个ListView,在这个ListView中显示所有的HouseLayer图层表

中的图元数据.
和以往不同的是,我们的程序界面做了一些改动,以跟踪数据的变化.
下图是窗口设计界面:
可以看到,我们在窗口左边放置了一个ListView控件,并在ListView中增加了4列(Columns)来显示数据.同时,把MapX控件的地图换成了我们自己

制作的"小区"地图.
在button1的单击事件button1_Click中编写如下代码:
MapXLib.Fields flds=new MapXLib.FieldsClass();
MapXLib.Layer lyr=axMap1.Layers._Item("HouseLayer");
MapXLib.Dataset dts=null;
flds.Add("ID","ID",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeString);
flds.Add("名称","名称",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeString);
flds.Add("月供年限","月供年限",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeInteger);
flds.Add("水电费","水电费",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeFloat);
dts=axMap1.DataSets.Add(MapXLib.DatasetTypeConstants.miDataSetLayer,lyr,lyr.Name,0,0,0,flds,false);
listView1.Items.Clear();
for(int i=1;i<=dts.RowCount;i++)
{
listView1.Items.Add( new ListViewItem(new string[]{dts[i,1].ToString(),
dts[i,2].ToString(),
dts[i,3].ToString(),
dts[i,4].ToString()}));
}
axMap1.DataSets.RemoveAll();
代码依旧很短,是对以前所介绍知识的进一步深化.这里要注意的是对dts的应用.运行程序,可以看到程序把所有的图元数据都正确地读取出来了

.
在程序末尾,我们将MapX控件中的DataSets全部移除,这是为了以后再使用DataSets方便.
2.添加数据(Data Adding)
在图层表上添加数据实际上就是添加图元,只不过这个图元是带有数据信息的.
仍然使用读取数据的例子,我们在窗口上增加一个按钮button2,编写它的单击事件代码button2_Click如下:
MapXLib.Feature ftr=new MapXLib.FeatureClass();
MapXLib.Points pts=new MapXLib.PointsClass();
MapXLib.Point pt=new MapXLib.PointClass();
MapXLib.RowValues rvs=new MapXLib.RowValuesClass();
MapXLib.Fields flds=new MapXLib.FieldsClass();
MapXLib.Layer lyr=axMap1.Layers._Item("HouseLayer");
MapXLib.Dataset dts=null;
flds.Add("ID","ID",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeString);
flds.Add("名称","名称",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeString);
flds.Add("月供年限","月供年限",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeInteger);
flds.Add("水电费","水电费",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeFloat);
dts=axMap1.DataSets.Add(MapXLib.DatasetTypeConstants.miDataSetLayer,lyr,lyr.Name,0,0,0,flds,false);
rvs=dts.get_RowValues(0);
rvs._Item("ID").Value="0003";
rvs._Item("名称").Value="C栋";
rvs._Item("月供年限").Value=20;
rvs._Item("水电费").Value=21.73;
ftr.Attach(axMap1.GetOcx());
ftr.Style=axMap1.Layers._Item("HouseLayer").Style;
ftr.Style.RegionPattern=MapXLib.FillPatternConstants.miPatternSolid;
ftr.Style.RegionColor=16711680;
ftr.Type=MapXLib.FeatureTypeConstants.miFeatureTypeRegion;
pt.Set(1,1);
pts.Add(pt,1);
pt.Set(2,1);
pts.Add(pt,2);
pt.Set(2,2);
pts.Add(pt,3);
pt.Set(1,2);
pts.Add(pt,4);
ftr=axMap1.FeatureFactory.CreateRegion(pts,ftr.Style);
ftr=axMap1.Layers._Item("HouseLayer").AddFeature(ftr,rvs);
ftr.Update(ftr,rvs);
axMap1.DataSets.RemoveAll();
在上面的程序中我们实现了将一个新的图元加入到图层表中,这个图元的数据信息如下表:
ID    名称  月供年限  水电费
0003  C栋     20      21.73
应该要注意的是我们首先还是使用了DataSets.Add将数据读出来,再使用get_RowValues得到行数据结构,然后才是对行数据的赋值.
运行程序,单击button1,可以看到左边的ListView中只有两条记录,再单击button2,看到图层上增加了一个蓝色的矩形图元,这就是我们增加的带

数据的图元,再单击button1,可以看到新增图元的数据信息出现在左边的ListView中.
3.修改数据(Data Modifying)
现在,要在窗口中添加另一个按钮button3了.这个按钮要实现的功能是将"A栋"的名称改成"A1栋".也就是说,我们要对A栋的数据进行修改.这个

按钮的代码如下:
MapXLib.FindFeature ftrRes=null;
MapXLib.Points pts=new MapXLib.PointsClass();
MapXLib.Point pt=new MapXLib.PointClass();
MapXLib.RowValues rvs=new MapXLib.RowValuesClass();
MapXLib.Fields flds=new MapXLib.FieldsClass();
MapXLib.Layer lyr=axMap1.Layers._Item("HouseLayer");
MapXLib.Dataset dts=null;
ftrRes=axMap1.Layers._Item("HouseLayer").Find.Search("0001","");
if (ftrRes.FindRC % 10==1)
{
flds.Add("ID","ID",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeString);
flds.Add("名称","名称",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeString);
flds.Add("月供年限","月供年限",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeInteger);
flds.Add("水电费","水电费",MapXLib.AggregationFunctionConstants.miAggregationSum,
MapXLib.FieldTypeConstants.miTypeFloat);
dts=axMap1.DataSets.Add(MapXLib.DatasetTypeConstants.miDataSetLayer,lyr,lyr.Name,0,0,0,flds,false);for (int

i=0;i<dts.RowCount;i++)
{
if (dts.get_Value(i,"ID").ToString().Trim()=="0001")
{
 rvs=dts.get_RowValues(i);
 rvs._Item("名称").Value="A1栋";
 ftrRes.Update(ftrRes,rvs);
  break;
 }
 }
axMap1.DataSets.RemoveAll();
}

可以看到,我们使用了前面章节所介绍的查找图元的技术.然而在给行数据赋值的时候仍然不得不在数据集中进行循环,以取得其它行数据,实际

上,如果通过控件(例如DataGrid或ListView)取到了图元的数据,是不必进行这样的循环的,直接对RowValue的所有字段都进行赋值就可以了.
4.删除数据(Data Deletion)
删除数据其实就是删除图元,只要找到图元,直接删除就可以了.但是要注意的是,因为图元包含了数据,所以在删除数据以后还要紧缩表.好在紧

缩表也十分简单.
仍然使用我们前面的例子,加一个button4,在它的单击事件中编写代码如下:
MapXLib.FindFeature ftrRes=null;
ftrRes=axMap1.Layers._Item("HouseLayer").Find.Search("0003","");
if (ftrRes.FindRC % 10 ==1)
{
axMap1.Layers._Item("HouseLayer").DeleteFeature(ftrRes);
}
//紧缩表
axMap1.Layers._Item("HouseLayer").Pack(MapXLib.LayerPackConstant.miPackAll);
如果在删除图元以后没有紧缩表的话,单击button1,将会看到ListView中多了一条空白的数据.
本章讲述的数据处理技术重在活学活用.关于数据处理还有一些重要的内容,例如专题图等技术,将在后面更为深入的章节中讲述.
练习:
1.在DataGrid中读取HouseLayer的所有图元数据,并将DataGrid内修改后的数据更新到图层表中.
2.使用自定义工具增加和删除带数据的图元.

在C#中怎样获取打印机的当前状态 ?
要获得打印机的状态,应该定义一个联合.
enum PrinterStatus
{
 其他状态= 1,
 未知,
 空闲,
 正在打印,
 预热,
 停止打印,
 打印中,
 离线
}

其中的"正在打印"和"打印中"是同一个意思,至于为什么会是这样,目前还不知道.

在程序中添加System.Management的引用:using System.Management;

然后编写获取打印机状态的函数如下:

/// <summary>
  /// 获取打印机的当前状态
  /// </summary>
  /// <param name="PrinterDevice">打印机设备名称</param>
  /// <returns>打印机状态</returns>
  private PrinterStatus GetPrinterStat(string PrinterDevice)
  {
   PrinterStatus ret=0;
   string path=@"win32_printer.DeviceId='"+PrinterDevice+"'";
   ManagementObject printer=new ManagementObject(path);
   printer.Get();
   ret=(PrinterStatus)Convert.ToInt32(printer.Properties["PrinterStatus"].Value);
   return ret;
  }

调用示例:

MessageBox.Show(GetPrinterStat("\\\\192.168.0.88\\Samsung SCX-4x16 Series").ToString());


实现两个ComboBox互动的代码
private const string m_strConnection=@"Jet OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Registry Path=;Jet OLEDB:Database

Locking Mode=1;Jet OLEDB:Database Password=;Data Source=""F:\源码\Study\TestTwoCombo\bin\Debug\data.mdb"";Password=;Jet

OLEDB:Engine Type=5;Jet OLEDB:Global Bulk Transactions=1;Provider=""Microsoft.Jet.OLEDB.4.0"";Jet OLEDB:System database=;Jet

OLEDB:SFP=False;Extended Properties=;Mode=Share Deny None;Jet OLEDB:New Database Password=;Jet OLEDB:Create System

Database=False;Jet OLEDB:Don't Copy Locale on Compact=False;Jet OLEDB:Compact Without Replica Repair=False;User ID=Admin;Jet

OLEDB:Encrypt Database=False";
private OleDbConnection cn=new OleDbConnection();
private OleDbDataAdapter da;
private DataTable dtbDept=new DataTable();
private DataTable dtbEmp=new DataTable();
private void Form1_Load(object sender, System.EventArgs e)
{
 m_ConnectToDB();
 da=new OleDbDataAdapter(@"SELECT * FROM 部门",cn);
 da.Fill(dtbDept);
 da.SelectCommand.CommandText=@"SELECT * FROM 员工";
 da.Fill(dtbEmp);
 m_CloseConnection();

 m_LoadDept();
}

/// <summary>
/// 连接数据库
/// </summary>
private void m_ConnectToDB()
{
 cn.ConnectionString=m_strConnection;
 if(cn.State==ConnectionState.Closed)
 {
  cn.Open();
 }
}

/// <summary>
/// 关闭数据库连接
/// </summary>
private void m_CloseConnection()
{
 if(cn.State==ConnectionState.Open)
 {
  cn.Close();
 }
}

/// <summary>
/// 加载部门信息
/// </summary>
private void m_LoadDept()
{
 if(dtbDept.Rows.Count>0)
 {
  cmbDept.DataSource=dtbDept;
  cmbDept.DisplayMember="部门名称";
 }
}

private void m_LoadEmp()
{
 if(cmbDept.SelectedIndex>=0)
 {
  dtbEmp.DefaultView.RowFilter="部门ID='"+dtbDept.Rows[cmbDept.SelectedIndex]["部门ID"].ToString().Trim()+"'";
  cmbEmp.DataSource=dtbEmp.DefaultView;
  cmbEmp.DisplayMember="姓名";
 }
}

private void cmbDept_SelectedIndexChanged(object sender, System.EventArgs e)
{
 m_LoadEmp();
}

转载于:https://www.cnblogs.com/yedi/articles/956272.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
arcgis开发教程,ao开发教程,arcobjects开发教程,arcgis objects开发教程,arcgis桌面开发教程,AE开发教程,Arcgis Engine开发教程 1.3. GeoDataBase 34 1.3.1. 如何加载Shape文件 34 1.3.2. 如何在ArcMap中加入Text和dBASE文件 35 1.3.3. 如何连接GeoDataBase文件 37 1.3.4. 如何连接Coverage文件 39 1.3.5. 如何连接栅格文件 41 1.3.6. 如何创建Shape文件 42 1.3.7. 如何创建DBF文件 45 1.3.8. 如何创建GeoDataBase文件 47 1.3.9. 如何创建Coverage文件 48 1.3.10. 如何建立文件连接(Join / Link) 50 1.3.11. 如何浏览纪录(属性查询) 52 1.3.12. 如何编辑记录 53 1.3.13. 如何增加记录 54 1.3.14. 如何删除记录 56 1.3.15. 如何纪录排序(ITableSort) 58 1.3.16. 如何添加字段 59 1.3.17. 如何删除字段 61 1.3.18. 如何进行空间查询 62 1.3.19. 如何进行高级空间查询(两个层之间的空间查询) 64 1.3.20. 如何进行层与层之间的逻辑运算 65 1.3.21. 如何将shape文件转化成GeoDataBase(各种文件格式的转换) 67 1.3.22. 如何将Map中显示的图形转化成栅格文件 70 1.3.23. 如何打开选中的层或独立表的属性窗口 71 1.3.24. 如何拷贝属性表中的一行 73 1.3.25. 如何为当前层或独立表创建一个Summary表 75 1.3.26. 如何利用用户定义的规则创建定制的排序 78 1.3.27. 如何实现在ArcMap上进行属性查询(Identify) 84 1.3.28. 如何设置和修改层的数据源 87 1.4. Display 88 1.4.1. 如何实现在ArcMap中放大缩小地图 88 1.4.2. 如何实现在ArcMap中移动地图 90 1.4.3. 如何实现在ArcMap上画Polygon 92 1.4.4. 如何实现在ArcMap上进行测量 94 1.4.5. 如何实现在ArcMap上选取中记录 100 1.4.6. 如何实现在ArcMap中进行动作的撤销和重做 101 1.4.7. 如何画Polygon Buffers 102 1.5. 图元编辑 104 1.5.1. 如何得到图形的基本属性 104 1.5.2. 如何将选中的点集转换成Polygon 105 1.5.3. 如何将Multipoint转换成Points 109 1.5.4. 如何通过Polygon中的多个Ring创建多个Polygon 111 1.5.5. 如何从Polyline创建Polygon 113 1.5.6. 如何从Polygon创建Polyline 115 1.5.7. 如何将Polygon/PolyCurve一般化(Generalize) 117 1.5.8. 如何获得Polygon的中点 119 1.5.9. 如何判断图形间的逻辑运算 121 1.5.10. 如何进行图形间的逻辑运算 124 1.5.11. 如何创建Envelope的Boundary 127 1.5.12. 如何通过鼠标移动图形 130 1.5.13. 如何为一个图形添加一个顶点 133 1.5.14. 如何删除一个图形上的一个顶点 136 1.5.15. 如何移动一个图形上的一个顶点 138 1.6. Element 141 1.6.1. 如何创建MarkerElement 141 1.6.2. 如何创建TextElement 142 1.6.3. 如何创建Balloon Callout 144 1.6.4. 如何创建PolygonElement 145 1.6.5. 如何选中一个Element 146 1.6.6. 如何移动Element 147 1.6.7. 如何排列Element 151 1.6.8. 如何通过名字查询Element 153 1.6.9. 如何拷贝Element 155 1.6.10. 如何沿着折线路径显示Text 158 1.7. Symbol和Renderer 159 1.7.1. 如何为一个层设置Simple Renderer 159 1.7.2. 如何为一个层设置UniqueValue Renderer 161 1.7.3. 如何为一个层设置ClassBreaks Renderer 165 1.7.4. 如何为一个层设置ProportionalSymbol Renderer 168 1.7.5. 如何为一个层设置Chart Renderer 170 1.7.6. 如何为一个层设置DotDensity Renderer 173 1.8. Layout和打印 175 1.8.1. 如何在Page Layout上添加Text 175 1.8.2. 如何在Page Layout上添加Legend 176 1.8.3. 如何在Page Layout上添加North Arrow 179 1.8.4. 如何在Page Layout上添加Scale bar 180 1.8.5. 如何在Page Layout上添加Scale Text 182 1.8.6. 如何在Page Layout上添加Picture 184 1.8.7. 如何创建、删除地图网格(Map Grid) 185 1.8.8. 如何设置Layout中MapFrame的外观风格属性 187 1.8.9. 何设置Layout中Page的边框(Border)和背景(Background) 189 1.8.10. 如何设置打印纸张的大小和方向 192 1.9. 坐标系统 193 1.9.1. 如何在ArcMap中设置地理坐标系和投影坐标系 193 1.9.2. 如何修改层的坐标系统 194 1.9.3. 如何把Polygon的顶点从经纬度坐标转换到平面直角坐标 196 1.10. ArcGis相关文件 198 1.10.1. 如何夹载grf文件 198 1.10.2. 如何新建指向Shape文件的lyr文件 199 1.10.3. 如何新建指向GeoDataBase文件的lyr文件 200 1.10.4. 如何加载mxd文件 202 1.10.5. 如何加载Apr文件(ArcView32) 203 1.10.6. 如何加载lyr文件 204 1.10.7. lyr文件的属性的设置 205 1.11. 其他 208 1.11.1. 如何创建简单的Column Chart 208 1.11.2. 如何将数据输出到Excel 209 1.11.3. 如何把Labels转换为Annotation 211 1.11.4. 如何把Annotation转换为Polygon Features 215 1.11.5. 如何设置Featurelayer的Label 218 1.11.6. 如何设置图层显示的透明度 220 1.11.7. 如何过滤层中要显示的Features 220 1.11.8. 如何在MapControl中新建一个Document并且保存 221

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值