上一篇文章介绍了一个简单的地图缩放工具的制作,接下来需要介绍一下地图数据读取及加载的设计。
首先,地图上的数据是来自数据库并自动生成的,我在这里并没有采用MapInfo的ADO.NET,而是采用本身系统的查询接口再加上自定义实体来生成地图图元,并插入MapInfo的Session中的临时表中以展示。
考虑到程序的扩展性,我将数据获取、图元展示、地图展示等分离开来,尽量做到灵活易懂。
数据获取接口,我只定义了一个方法:
Code

/**//// <summary>
/// 数据提供接口,定义了获取数据的基本方法
/// </summary>
public interface IDataProvider

{

/**//// <summary>
/// 获取所有数据主方法
/// </summary>
/// <returns>获取到的实体列表</returns>
List<AbstractEntity> GetData ();
}
这个方法返回List<自定义抽象实体>,这个List表示多个需要展示的图元集合。
所以最重要的是AbstractEntity了。
在该抽象实体中,我定义了两个属性X和Y,用来表示图元的坐标:
公用属性

/**//// <summary>
/// 地图横向坐标X(经度)
/// </summary>
public double X

{
get

{
return this._x;
}
set

{
this._x = value;
}
}

/**//// <summary>
/// 地图纵向坐标Y(纬度)
/// </summary>
public double Y

{
get

{
return this._y;
}
set

{
this._y = value;
}
}
然后就是定义一大堆抽象方法了:
抽象方法

/**//// <summary>
/// 获取该子类实例化在地图上的显示样式
/// </summary>
/// <returns></returns>
public abstract CompositeStyle GetMapStyle ();

/**//// <summary>
/// 获取该子类实例在地图上显示的图元形状
/// </summary>
/// <param name="coordSys"></param>
/// <returns></returns>
public abstract FeatureGeometry GetFeature ( CoordSys coordSys );

/**//// <summary>
/// 构造该子类在地图表中的自定义字段
/// </summary>
/// <remarks>
/// 不应包含X、Y、Key字段
/// 字段名“MI_Geometry”和“MI_Style”和“MI_Key”为保留字段名
/// </remarks>
/// <returns>自定义列列表</returns>
public abstract List<Column> CreateCustomColumn ();

/**//// <summary>
/// 填充Command对象中Parameters的值。只需填充除父类外的自定义属性
/// </summary>
/// <remarks>该方法只允许被父类调用</remarks>
/// <param name="command">MICommand对象引用</param>
protected abstract void FillCommand ( ref MICommand command );

/**//// <summary>
/// 构造该子类在地图上显示的标注图层
/// </summary>
/// <returns>如不需显示标注图层,返回NULL</returns>
public abstract IMapLayer CreateLabelLayer ();

/**//// <summary>
/// 获取该子类在地图数据表表名
/// </summary>
/// <returns></returns>
public abstract string GetTableName ();

/**//// <summary>
/// 获取子类在地图上图层的名称
/// </summary>
/// <returns>数据在图层上的名称</returns>
public abstract string GetLayerName ();

/**//// <summary>
/// 获取该实体的唯一标识
/// </summary>
/// <returns></returns>
public abstract string GetKey ();

/**//// <summary>
/// 构造该图形被点击后在地图上弹出的附加控件
/// </summary>
/// <param name="key">被点击图形的唯一标识,该标识由Entity中GetKey获取</param>
/// <returns></returns>
public abstract System.Windows.Forms.Control SelectionTips(string key);
从上面代码可以看出,在同一个List<AbstractEntity>中,只要把不同的子类对象装到List中,在地图上显示的所有图元都可以不相同!
以下展示了其中一个子类的重写:
Code
public override MapInfo.Styles.CompositeStyle GetMapStyle ()

{
Color cc = Color.FromArgb(200, GetValueColor(this.Value));
SimpleInterior siStyle = new SimpleInterior(2, cc);
SimpleLineStyle lineStyle = new SimpleLineStyle ( new LineWidth () );
AreaStyle aStyle = new AreaStyle ( lineStyle, siStyle );
CompositeStyle style = new CompositeStyle ( aStyle );
return style;
}
public override sealed List<MapInfo.Data.Column> CreateCustomColumn ()

{
MapInfo.Data.Column c = new MapInfo.Data.Column ( "value", MapInfo.Data.MIDbType.Double );
List<MapInfo.Data.Column> list = new List<MapInfo.Data.Column> ();
list.Add ( c );
return list;
}
protected override sealed void FillCommand ( ref MapInfo.Data.MICommand command )

{
command.Parameters["value"].Value = this._value;
}
public override MapInfo.Geometry.FeatureGeometry GetFeature ( MapInfo.Geometry.CoordSys coordSys )

{
//构造一个边长100米的矩形
MapInfo.Geometry.Rectangle dr = new MapInfo.Geometry.Rectangle ( coordSys, new DPoint ( this.X, this.Y ), 100d, 100d, DistanceUnit.Meter, DistanceType.Spherical );
FeatureGeometry fg = new MapInfo.Geometry.Rectangle ( coordSys, dr );
return fg;
}
其中CreateCustomColumn和FillCommand方法是比较重要的,我们来分析一下:
由于现在我使用MapInfo中临时表来插入图元数据,并需要插入一些适当的值到自定义列中,于是在CreateCustomColumn中,我由子类提供一个列列表,以便构造Command对象时使用,并使用FillCommand方法把适当的值插入。这样,子类也具有了在临时图元表中插入自定义值的可能。在地图获取到数据后,只要把所有的数据转换成MapInfo可识别的图元,并插入到临时图元表中,那么所有需要的图元都将出现在地图上了!
填充数据到临时图元表中

/**//// <summary>
/// 把数据填充到地图表中
/// </summary>
/// <param name="table">地图数据表实例,必须实现GetFeature和GetMapStyle方法</param>
/// <param name="coordSys">地图坐标系统</param>
/// <param name="entityList">数据</param>
public static void InsertTable ( Table table,CoordSys coordSys, List<AbstractEntity> entityList )

{
//创建连接对象
MIConnection connection = new MIConnection ();
connection.Open ();
//Comm对象
MICommand cmd;
try

{
foreach ( AbstractEntity entity in entityList )

{
cmd = connection.CreateCommand ();
//使用各个实体构造Comm对象
entity.PrepareCommand ( table.Alias, ref cmd, entity.GetFeature ( coordSys ), entity.GetMapStyle () );
cmd.Prepare ();
int nchanged = cmd.ExecuteNonQuery ();
cmd.Dispose ();
}
}
catch ( Exception ex )

{
throw new Exception ( "InsertTable Error " + ex.Message, ex );
}
finally

{
if ( connection.State == System.Data.ConnectionState.Open )

{
connection.Close ();
}
}
}