====== Source Code ServicesEditionSample OledbPointFeatureSource CS 090728.zip ======
====OledbPointFeatureLayer.cs====
using ThinkGeo.MapSuite.Core;
namespace OledbPointFeatureSource
{
// The FeatureLayer is a wrapper to the FeatureSource and provides all of the drawing specific
// methods such as the ZoomLevels and Styles. As you can see it is just a simple wrapper and the
// real work is already done for you in the FeatureLayer base class.
class OledbPointFeatureLayer: FeatureLayer
{
OledbPointFeatureSource oledbPointFeatureSource;
// It is important for compatability that you always have a default constructor that
// takes no parameters. This constructor will just chain to the more complex one.
public OledbPointFeatureLayer()
: this(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)
{ }
// We have provided another constructor that has all of the parameters we need for the FeatureLayer
// to work.
public OledbPointFeatureLayer(string tableName, string idColumnName, string xColumnName, string yColumnName, string connectionString)
: base()
{
// Here is where we create our FeatureSource and set the internal property on the FeatureLayer
oledbPointFeatureSource = new OledbPointFeatureSource(tableName, idColumnName, xColumnName, yColumnName, connectionString);
this.FeatureSource = oledbPointFeatureSource;
}
// The next dozen lines are all of the properties we need. It is good form to always match
// the parameters in your constructors with properties of the exact same name.
public string TableName
{
get { return oledbPointFeatureSource.TableName; }
set { oledbPointFeatureSource.TableName = value; }
}
public string ConnectionString
{
get { return oledbPointFeatureSource.ConnectionString; }
set { oledbPointFeatureSource.ConnectionString = value; }
}
public string XColumnName
{
get { return oledbPointFeatureSource.XColumnName; }
set { oledbPointFeatureSource.XColumnName = value; }
}
public string YColumnName
{
get { return oledbPointFeatureSource.YColumnName; }
set { oledbPointFeatureSource.YColumnName = value; }
}
public string IdColumnName
{
get { return oledbPointFeatureSource.IdColumnName; }
set { oledbPointFeatureSource.IdColumnName = value; }
}
}
}
====OledbPointFeatureSource.cs====
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.OleDb;
using ThinkGeo.MapSuite.Core;
namespace OledbPointFeatureSource
{
class OledbPointFeatureSource : FeatureSource
{
private OleDbConnection connection;
private string connectionString;
private string tableName;
private string idColumnName;
private string xColumnName;
private string yColumnName;
// It is important for compatability that you always have a default constructor that
// takes no parameters. This constructor will just chain to the more complex one.
public OledbPointFeatureSource()
: this(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)
{ }
// We have provided another constructor that has all of the parameters we need for the FeatureSource
// to work.
public OledbPointFeatureSource(string tableName, string idColumnName, string xColumnName, string yColumnName, string connectionString)
: base()
{
TableName = tableName;
IdColumnName = idColumnName;
XColumnName = xColumnName;
YColumnName = yColumnName;
ConnectionString = connectionString;
}
// The next dozen lines are all of the properties we need. It is good form to always match
// the parameters in your constructors with properties of the exact same name.
public string TableName
{
get { return tableName; }
set { tableName = value; }
}
public string ConnectionString
{
get { return connectionString; }
set { connectionString = value; }
}
public string XColumnName
{
get { return xColumnName; }
set { xColumnName = value; }
}
public string YColumnName
{
get { return yColumnName; }
set { yColumnName = value; }
}
public string IdColumnName
{
get { return idColumnName; }
set { idColumnName = value; }
}
// Use the OpenCore to initialize your underlying data source. The concreat Open method will ensure
// that if the user calls the Open method multiple times in a row that you only get one call to
// OpenCore.
protected override void OpenCore()
{
connection = new OleDbConnection(connectionString);
connection.Open();
}
// Use the CloseCore to close your underlying data source. It is important to note that the
// CloseCore is not like the Dispose on other objects. The FeatureSource is meant to be opened
// and closed many times durring its lifetime. Make sure that you clean up any objects that have
// unmanaged resources but do not put the object in a state that when Open is called it will fail.
// The concreat Close method will ensure that if the user calle the Close multiple times in
// a row that you only get one call to CloseCore.
protected override void CloseCore()
{
connection.Close();
}
// Here you need to query all of the features in your data source. We use this method
// as the basis of nearly all other virtual methods. For example if you choose not to
// override the GetCountCore then we will get all the features and count them as the default.
// This is ineffecient however it produces the correct results.
protected override Collection GetAllFeaturesCore(IEnumerable columnNames)
{
OleDbCommand command = null;
OleDbDataReader dataReader = null;
Collection returnFeatures = new Collection();
// Alays be sure to wrap imporant code that accesses resources that need
// to be closed. In the Finally we will ensure they always get cleaned up.
try
{
// We need to construct the part of the SQL statement for retuning the
// column data. We only return the columns asked for byt the columnNames
// parameter of the function. This ensures we do not get more than we need.
string columnsSQL = string.Empty;
foreach (string columnName in columnNames)
{
columnsSQL += "," + columnName;
}
// Here we build up and execute the query string using the columns the users defined in the properties
// such as the XColumnName and IdColumnName.
command = new OleDbCommand("SELECT " + idColumnName + " as TG_ID, " + xColumnName + " as TG_X, " + yColumnName + " as TG_Y " + columnsSQL + " FROM " + tableName, connection);
dataReader = command.ExecuteReader();
// We now loop though all of the results and build up our features that we need to return.
while (dataReader.Read())
{
PointShape pointShape = new PointShape(Convert.ToDouble(dataReader["TG_X"]), Convert.ToDouble(dataReader["TG_Y"]));
pointShape.Id = dataReader["TG_ID"].ToString();
Feature feature = pointShape.GetFeature();
// This small part populates the column values that were requested. They are data
// such as columns used for ClassBreakStyles or TextStyles for labeling.
foreach (string columnName in columnNames)
{
feature.ColumnValues.Add(columnName, dataReader[columnName].ToString());
}
returnFeatures.Add(feature);
}
}
finally
{
// Cleanup any of the objects that need to be closed or disposed.
if (command != null) { command.Dispose(); }
if (dataReader != null) { dataReader.Dispose(); }
}
return returnFeatures;
}
// Though this method is not required for creating our new class it is an important one.
// This method is used to get only the features inside of the bounding box passed in. The reason
// this is critical is that many other methods on the QueryTools such as Touches, Overlaps, Intersects,
// and many others use this method as a first pass filter. If you do not override this method then
// the default code calls the GetAllFeatures and look at each to see if it is in the bounding box.
// While this method will produce the correct result it will not perform as well as your custom code.
protected override Collection GetFeaturesInsideBoundingBoxCore(RectangleShape boundingBox, IEnumerable returningColumnNames)
{
OleDbCommand command = null;
OleDbDataReader dataReader = null;
Collection returnFeatures = new Collection();
// Alays be sure to wrap imporant code that accesses resources that need
// to be closed. In the Finally we will ensure they always get cleaned up.
try
{
// We need to construct the part of the SQL statement for retuning the
// column data. We only return the columns asked for byt the columnNames
// parameter of the function. This ensures we do not get more than we need.
string columnsSQL = string.Empty;
foreach (string columnName in returningColumnNames)
{
columnsSQL += "," + columnName;
}
// This whereSql is important becasue it is what is used to determine if the point is in
// the bounding box passed in. While it is a bit complex it get your results quickly in
// large datasets so long as the X & Y columns are indexed.
string whereSql = " " + xColumnName + " <= " + boundingBox.LowerRightPoint.X + " AND " + xColumnName + " >= " + boundingBox.UpperLeftPoint.X + " AND " + yColumnName + " <= " + boundingBox.UpperLeftPoint.Y + " AND " + yColumnName + " >= " + boundingBox.LowerRightPoint.Y;
command = new OleDbCommand("SELECT " + idColumnName + " as TG_ID, " + xColumnName + " as TG_X, " + yColumnName + " as TG_Y " + columnsSQL + " FROM " + tableName + " WHERE " + whereSql, connection);
dataReader = command.ExecuteReader();
// We now loop though all of the results and build up our features that we need to return.
while (dataReader.Read())
{
Feature feature = new Feature(Convert.ToDouble(dataReader["TG_X"]), Convert.ToDouble(dataReader["TG_Y"]), dataReader["TG_ID"].ToString());
// This small part populates the column values that were requested. They are data
// such as columns used for ClassBreakStyles or TextStyles for labeling.
foreach (string columnName in returningColumnNames)
{
feature.ColumnValues.Add(columnName, dataReader[columnName].ToString());
}
returnFeatures.Add(feature);
}
}
finally
{
// Cleanup any of the objects that need to be closed or disposed.
if (command != null) { command.Dispose(); }
if (dataReader != null) { dataReader.Dispose(); }
}
return returnFeatures;
}
// This method returns all of the columns in the data source. This method is not required however
// if it is not overridden then the FeatureSource will not have any columns available to it.
// Since having access to the column data is usefull for labeling and such we suggest you override it.
protected override Collection GetColumnsCore()
{
OleDbCommand command = null;
OleDbDataReader dataReader = null;
Collection returnColumns = new Collection();
// Alays be sure to wrap imporant code that accesses resources that need
// to be closed. In the Finally we will ensure they always get cleaned up.
try
{
// Here we have a query that will quickly return nothing. As strange as it sounds it is a
// good way to get the table structure back without having to return any column data.
command = new OleDbCommand("SELECT * FROM " + tableName + " WHERE 1=2", connection);
dataReader = command.ExecuteReader();
// We now loop through and create our column list. In the FeatureSourceColumn we can
// optionally provide the column type but it is just informational so we didn't code it.
for (int i = 0; i < dataReader.FieldCount; i++)
{
FeatureSourceColumn featureSourceColumn = new FeatureSourceColumn(dataReader.GetName(i));
returnColumns.Add(featureSourceColumn);
}
}
finally
{
// Cleanup any of the objects that need to be closed or disposed.
if (command != null) { command.Dispose(); }
if (dataReader != null) { dataReader.Dispose(); }
}
return returnColumns;
}
// This is another method that does not need to be overridden but we suggest that you do.
// This method gets the cound of all the features in the data source. If you choose not to
// override it then the default will call the GetAllFeatures and count them. This is not very
// effecient so we suggest you override it.
protected override int GetCountCore()
{
OleDbCommand command = null;
int count = 0;
// Alays be sure to wrap imporant code that accesses resources that need
// to be closed. In the Finally we will ensure they always get cleaned up.
try
{
// Here we do a standard SQL count statement and return the results.
command = new OleDbCommand("SELECT COUNT(*) FROM " + tableName, connection);
count = Convert.ToInt32(command.ExecuteScalar());
}
finally
{
// Cleanup any of the objects that need to be closed or disposed.
if (command != null) { command.Dispose(); }
}
return count;
}
}
}
====Program.cs====
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace OledbPointFeatureSource
{
static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new TestForm());
}
}
}
====TestForm.cs====
using System;
using System.Drawing;
using System.Windows.Forms;
using ThinkGeo.MapSuite.Core;
namespace OledbPointFeatureSource
{
public partial class TestForm : Form
{
private MapEngine mapEngine = new MapEngine();
private Bitmap bitmap = null;
public TestForm()
{
InitializeComponent();
}
private void TestForm_Load(object sender, EventArgs e)
{
// Set the full extent and the background color
mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(new RectangleShape(-180.0, 83.0, 180.0, -90.0), Map.Width, Map.Height);
mapEngine.BackgroundFillBrush = new GeoSolidBrush(GeoColor.GeographicColors.DeepOcean);
// Setup the cities layer - OledbPointFeatureSource
string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=..\..\data\Cities.mdb;User Id=admin;Password=;";
OledbPointFeatureLayer citiesLayer = new OledbPointFeatureLayer("Cities", "ID", "X", "Y", connectionString);
citiesLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City1;
citiesLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.City1("CityName"); ;
citiesLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
// Setup the countries layer
ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(@"..\..\data\Countries02.shp",ShapeFileReadWriteMode.ReadOnly);
worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
// Add the new layers to the MapEngine
mapEngine.StaticLayers.Add("WorldLayer", worldLayer);
mapEngine.StaticLayers.Add("CitiesLayer", citiesLayer);
DrawImage();
}
private void btnGetCount_Click(object sender, EventArgs e)
{
FeatureLayer citiesLayer = (FeatureLayer)mapEngine.StaticLayers["CitiesLayer"];
citiesLayer.Open();
MessageBox.Show("Number of cities: " + citiesLayer.FeatureSource.GetCount(), "Get Count");
citiesLayer.Close();
}
private void DrawImage()
{
if (bitmap != null) { bitmap.Dispose(); }
bitmap = new Bitmap(Map.Width, Map.Height);
mapEngine.OpenAllLayers();
mapEngine.DrawStaticLayers(bitmap, GeographyUnit.DecimalDegree);
mapEngine.CloseAllLayers();
Map.Image = bitmap;
}
private void ToolBar_ButtonClick(object sender, ToolBarButtonClickEventArgs e)
{
switch (e.Button.Tag.ToString())
{
case "Zoom In":
mapEngine.CurrentExtent.ScaleDown(50);
break;
case "Zoom Out":
mapEngine.CurrentExtent.ScaleUp(50);
break;
case "Full Extent":
mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(new RectangleShape(-180.0, 83.0, 180.0, -90.0), Map.Width, Map.Height);
break;
case "Pan Left":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Left, 40);
break;
case "Pan Right":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Right, 40);
break;
case "Pan Up":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Up, 20);
break;
case "Pan Down":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Down, 20);
break;
default:
break;
}
DrawImage();
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
}
}