Highlight selected features like ArcMap in ArcGIS Server using WEBADF

In the below code I'm going to show how to highlight the selected features on ArcGIS Server Map with aqua color like you do in ArcMap. In here I'm highlighting the features that are output of a Attribute query. But you can get the features to highlight from spatial query or anyother methods.




Copy & Paste :



int resourceIndex = 0;
System.Data.DataTable datatable = null;
ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality mf =
(ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality)Map1.GetFunctionality(resourceIndex);
ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceBase ags_mrb =
(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceBase)mf.Resource;
ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription[] layerdescs = ags_mrb.MapDescription.LayerDescriptions;
ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisresource = mf.Resource;
bool supported = gisresource.SupportsFunctionality(typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality));
if (supported)
{
ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality qfunc;
qfunc = (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)
gisresource.CreateFunctionality(typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null);
string[] lids;
string[] lnames;
qfunc.GetQueryableLayers(null, out lids, out lnames);
ESRI.ArcGIS.ADF.Web.SpatialFilter spatialfilter = new ESRI.ArcGIS.ADF.Web.SpatialFilter();
spatialfilter.ReturnADFGeometries = false;
spatialfilter.MaxRecords = 1000;
spatialfilter.WhereClause = "USECODE = '101'";
datatable = qfunc.Query(null, lids[0], spatialfilter);
}
ESRI.ArcGIS.ADF.ArcGISServer.RgbColor irgbc = new ESRI.ArcGIS.ADF.ArcGISServer.RgbColor();
irgbc.Red = 50;
irgbc.Green = 255;
irgbc.Blue = 255;
irgbc.AlphaValue = 255;
//build the array of objectids, could perform a query but since we already know id we don't have to.
ESRI.ArcGIS.ADF.ArcGISServer.FIDSet fids = new ESRI.ArcGIS.ADF.ArcGISServer.FIDSet();
int[] ids = new int[datatable.Rows.Count];
for (int i = 0; i < datatable.Rows.Count; i++)
{
DataRow dr = datatable.Rows[i];
ids[i] = Convert.ToInt32(dr[0]);
}
fids.FIDArray = ids;
layerdescs[0].SelectionColor = irgbc;
layerdescs[0].SelectionFeatures = fids.FIDArray;
Map1.Refresh();
response = Map1.CallbackResults.ToString();

Incorrect radius Measure tool ArrcGIS Server 9.3 CircleEventArgs

bug: NIM036015 MapCircleEventArgs and CircleEventArgs donot report the right Screen and Map radius.

Workaround: Access the MapCircleEventsArgs MapRadius property and perform additional calculations. To determine the correct map radius, divide the MapCircleEventsArgs MapRadius value by 4. To determine the correct screen radius, divide the MapCircleEventsArgs MapRadius value by 4 and then divide the result by the map to screen ratio (resolution).

public void ServerAction(ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs args)
{
Map mmap = args.Control as Map;
MapCircleEventArgs mcea = (MapCircleEventArgs)args;

double maptoscreenratio = mmap.Extent.Width / mmap.ViewWidth;
double mapradius = mcea.MapRadius / 4;
double screenradius = (mcea.MapRadius / 4) / maptoscreenratio;
System.Diagnostics.Debug.Print("Map To Screen Ratio: {0}", maptoscreenratio);
System.Diagnostics.Debug.Print("Map Radius: {0} units)", mapradius);
System.Diagnostics.Debug.Print("Screen Radius: {0} pixels)", screenradius);
}

Address locator in ArcGIS Server webapp always returning all candidates irrespective of score

If you are setting the minimum candidate score to 100 in your address in ArcGIS Server web application, when you use it in geocoding task and if its always returning all the candidates with all candidates above score 60 irrespective of minimum candiate score set in address locator then you are in the right place.

Its actually a bug NIM037331. So no matter what match score you assign in your address locator, when you add it in as a task, it always goes to 60. You need to find the below line in default.aspx and replace 60 to whatever you want.

esri:GeocodeResourceItem ShowAllCandidates="False" MinCandidateScore="10" MinMatchScore="60"

ESRI.ArcGIS.VE.Config.Proxy is not set

Error : ESRI.ArcGIS.VE.Config.Proxy is not set

If you are trying to run a esri.tasks task (buffer,find,query,identify..) in ArcGIS Server 9.3 Virtual Earth extension SDK and you get the above error then most probably the cause should be because your query length exceeded 2000 characters. Before you proceed further make sure that the same task runs if you choose a smaller area or smaller number of features (basically smaller in quanitity). If it works then you got yourself a free pass for the IMAX Experience :).

When you perform any one of the esri.tasks then the relevant task information is submitted to the ArcGIS Service as a query string. The standard browser limit for a URL is 2000 characters. So when your task creates a URL request of size greater than 2000 characters , it fails and you get the error 'esriConfig.defaults.io.proxyUrl is not set '.

Solution:
To solve the above issue you have the install the proxy page. when you install the proxy page on your web serverand initialize
esriConfig.defaults.io.proxyUrl, your service requests will be sent to the proxy page(proxy.ashx). Then your proxy page will forward the request to the ArcGIS Service.

Installing proxy page:

a. Download the the proxy page at http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jshelp/ProxyPage_NET.zip(contains proxy.ashx and proxy.config)
b. Extract the zip file and copy the proxy.ashx somewhere that is accesible through your IIS or in your c:\inetpub directory structure.

c. Copy the proxy.config in to your application root (root directory of the application in which copied your proxy.ashx).

d. open your proxy.config and add a tag
Fig 1 : If you just want to use proxy only for a single service



Fig 2: If you want to use proxy for all the services on the ArcGIS Server

Also you can add multiple single service service URLs(Fig 1) each for a
different service.

e. Place ESRI.ArcGIS.VE.Config.Proxy = "proxy.ashx" in your init() function of your javascript code.


This should take care of the error "ESRI.ArcGIS.VE.Config.Proxy is not set". But if you get the error even after installing the proxy feel free to post a comment and we will look into it.







Session has timed out from extended inactivity - ArcGIS Server WebADF timeout

'Session has timed out from extended inactivity ' in ArcGIS server application occurs due to the WEBADF timeout thats set in display_common.js file , which is streamed to the browser at run time. In order to change the timeout you must initialize the maximumLapseTime with new value. But you have to make sure that this piece of javascript executes after display_common.js is streamed into the browser (after the controls are loaded). You can do that by adding the below piece of code to page_load function.
protected void Page_Load(object sender, EventArgs e)
{

m_page = m_map.Page;
int MyTimeout = 100;
string timeoutstr = "var maximumLapseTime = " + MyTimeout.ToString + ";";
if (!m_page.ClientScript.IsClientScriptBlockRegistered("TimeoutScript"))
m_page.ClientScript.RegisterClientScriptBlock(m_page.GetType(), "TimeoutScript",timeoutstr);


}

If you want to change the timeout message please add the below code to your page load to override showLapseAlert() in display_common.js
protected void Page_Load(object sender, EventArgs e)

{
m_page = m_map.Page;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(" ");
if (!m_page.ClientScript.IsClientScriptBlockRegistered("showlapseScript"))
m_page.ClientScript.RegisterClientScriptBlock(m_page.GetType(), "showlapseScript",sb);

}

Copy features from feature class to shape file or feature class to feature class

private void copyFeatureClass(IFeatureClass sourceFeatureClass, IFeatureClass targetFeatureClass, IQueryFilter myQueryFilter)
{
IFeatureCursor mySourceFeatureCursor = sourceFeatureClass.Search(myQueryFilter, false);
IFeature mySourceFeature = mySourceFeatureCursor.NextFeature();
string mySourceFieldName;
int myTargetFieldId;
while (mySourceFeature != null)
{
IFeature myFeature = targetFeatureClass.CreateFeature();
IFeatureSimplify myFeatureSimplify = myFeature as IFeatureSimplify;
IGeometry myGeometry = mySourceFeature.ShapeCopy;
myFeatureSimplify.SimplifyGeometry(myGeometry);
myFeature.Shape = myGeometry;
for (int i=1; i LESS THAN mySourceFeatureCursor.Fields.FieldCount; i++)
{
try
{
mySourceFieldName = mySourceFeatureCursor.Fields.get_Field(i).Name; // Name of field in target feature
if (!(mySourceFieldName == sourceFeatureClass.ShapeFieldName
(sourceFeatureClass.LengthField != null && mySourceFieldName == sourceFeatureClass.LengthField.Name)
(sourceFeatureClass.AreaField != null && mySourceFieldName == sourceFeatureClass.AreaField.Name))) // Don't do shape fields
{
myTargetFieldId = targetFeatureClass.FindField(mySourceFieldName); // Id of field in source feature
myFeature.set_Value(myTargetFieldId, mySourceFeature.get_Value(i)); // Copy value
}
}
catch(ComException e)
{
string ComEx = e.Message;
}
}
myFeature.Store();
mySourceFeature = mySourceFeatureCursor.NextFeature();
}
}

Printing a ArcGIS Server map with all resources

public void printArcGISMap(string printTitle)
{

string printTitle = m_queryString["PrintTitle"];
ArrayList bitmaps = new ArrayList();
ArrayList imgAttributes = new ArrayList();
double imgheight = 400;
double imgwidth = 600;

foreach (IMapFunctionality mf in Map1.GetFunctionalities())
{
if (!mf.DisplaySettings.Visible) continue;
mf.DisplaySettings.ImageDescriptor.Height = Convert.ToInt32(imgheight);
mf.DisplaySettings.ImageDescriptor.Width = Convert.ToInt32(imgwidth);
mf.DisplaySettings.ImageDescriptor.TransparentBackground = true;
mf.DisplaySettings.ImageDescriptor.ImageFormat = ESRI.ArcGIS.ADF.Web.ImageFormat.PNG8;
// Get the data source's transparency and convert it to alpha value.
// We will apply this alpha value when overlaying each resource map image the graphics.
float fTransparency = mf.DisplaySettings.Transparency;
if (fTransparency == 0) fTransparency = 1;
//Since the transparency is in whole number, need to conver it to decimal percent (ie 100 - 20 * .01 = .8)
else fTransparency = (float)(100 - fTransparency * .01);
ImageAttributes ia = setImageAttributes(fTransparency);
ESRI.ArcGIS.ADF.Web.MapImage mi = mf.DrawExtent(Map1.Extent);
//Store the image and image attribute in two separate ArrayLists
if (mi != null)
{

bitmaps.Add(mi.GetImage());
imgAttributes.Add(ia);
}

}

float fimgwidth = (float)700;
float fimgheight = (float)560;
Bitmap newimg = new System.Drawing.Bitmap(int.Parse(fimgwidth.ToString()), int.Parse(fimgheight.ToString()));
//Bitmap newimg = new Bitmap((System.Drawing.Image)bitmaps[bitmaps.Count - 1]);
Graphics imggraphics = System.Drawing.Graphics.FromImage(newimg);
imggraphics.FillRectangle(new System.Drawing.SolidBrush(System.Drawing.Color.White), 0, 0, fimgwidth, fimgheight);
// Draw the border
Pen drawingPen = new Pen(new SolidBrush(Color.Black), 3);
imggraphics.DrawRectangle(drawingPen, new Rectangle(25, 25, 650, 510));
// draw the title box
imggraphics.DrawRectangle(drawingPen, new Rectangle(25, 445, 125, 90));
imggraphics.DrawRectangle(drawingPen, new Rectangle(150, 445, 525, 90));
//draw the title and date printed
Font fnt = new Font("Times New Roman", 24, System.Drawing.FontStyle.Bold, GraphicsUnit.Pixel);
imggraphics.DrawString(printTitle, fnt, new SolidBrush(Color.Black), 300, 475);
fnt = new Font("Times New Roman", 12, System.Drawing.FontStyle.Italic, GraphicsUnit.Pixel);
DateTime today = DateTime.Now;
imggraphics.DrawString("Printed on " + today.ToString(), fnt, new SolidBrush(Color.Gray), 300f, 503f);
// Draw the north arrow
fnt = new Font("ESRI North", 55, System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel);
imggraphics.DrawString("O", fnt, new SolidBrush(Color.Gray), 70f, 455f);
for (int j = bitmaps.Count - 1; j >= 0; j--)
{
System.Drawing.Bitmap bmp = (Bitmap)bitmaps[j];
if (j == bitmaps.Count - 1) // first draw the base
imggraphics.DrawImage(bmp, 50, 35, (float)bmp.Width, (float)bmp.Height);
else
{
int iWidth = bmp.Width;
int iHeight = bmp.Height;
imggraphics.DrawImage(
bmp,
new Rectangle(50, 35, bmp.Width, bmp.Height),
0.0f,
0.0f,
(float)bmp.Width,
(float)bmp.Height,
GraphicsUnit.Pixel,
(ImageAttributes)imgAttributes[j]); //Image attribute for selected image; this has the transparency
}
//bmp.Save(@"c:\temp\img_" + j + ".bmp"); // Try saving each of the resource map image to a file so you can preview
//newimg.Save(@"c:\temp\newimg_" + j + ".bmp");
}
imggraphics.Dispose();
string imgPath =Request.PhysicalApplicationPath + "\\map_images\\";
string imgName = System.Guid.NewGuid().ToString() + ".jpg";

newimg.Save(imgPath + imgName );
System.Drawing.Printing.PrintDocument printD = new System.Drawing.Printing.PrintDocument();
script = "openImage('map_images/" + imgName + "');"; // This is a javascript that opens the map print image in a new window
Map1.CallbackResults.Add(new CallbackResult(null, null, "JavaScript", script));
_callbackresults = Map1.CallbackResults.ToString(); // Add it as a call back for the client to handle it. This is another topic you can find instruction on

}



// ImageAttributes sets up the alpha value for an image.
private ImageAttributes setImageAttributes(float alP)
{
// Initialize the color matrix.
// Note the value 0.8 in row 4, column 4.
float[][] matrixItems ={
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, alP, 0}, // Here is where the alpha value is applied.
new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(matrixItems);
// Create an ImageAttributes object and set its color matrix.
ImageAttributes imageAtt = new ImageAttributes();
imageAtt.SetColorMatrix(
colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
return imageAtt;
}

Quantum GIS A complete free Desktop GIS software

Quantum GIS is a widely used open source GIS Desktop software for viewing , editing and analyzing GIS data. For folks who couldn’t afford the hefty licenses for GIS Desktop tools , Quantum GIS is really a option. Today we are going to go through some of the important features Quantum GIS offer to the GIS Community.




With Quantum GIS you will be able to work with four different types of GIS data sources i.e. vector layer, Raster Layer, PostGIS Layer, WMS Layer. With the vector layer option you can add ESRI Shapefile (.shp), MapInfo,SDTS ( Spatial Data Transfer Standard) and GML files. Raster layer option gives you the ability to add files that is of almost any raster type available.








Quantum GIS provides all the basic map navigation tools and also Measure line, Measure Area, ZoomToLayer, ZoomToSelection, Identify, Select Features, Bookmarks, map tips. Just like in the ArcMap you can open the attribute table and search the data with different field values. It also has a neat query builder just like ArcView that helps you in building a custom query.




One of the features that very expensive otherwise is Editing the GIS Data. Quantum GIS provides you the ability to edit the fetures in both attribute table and on the map. Editing toolbar in Quantum GIS has Split Features, Move Features, Move Vertex, Add Vertex, Delete Vertex, Delete Selected, Cut Features, Copy Features, Paste Features, Capture Point, Capture Line, Capture Polygon, Add Ring, Add Island tools. These are all the tools used by GIS data analysts most of the times for creating and modifying features. Using Quantum GIS you can define your own custom project which comes handy for cartographers when creating new maps.


Quantum GIS comes with a different variety of cool plugins like

Georeferencer - for georeferencing raster files.
CopyrightLabel - Draws copyright information
GPS Tools - Tools for loading and importing GPS data
GRASS - for GRASS layer
Graticule Creator - Builds a graticule
MapServer Export - Export a QGIS project file to a MapServer map file
PostgreSQL Geoprocessing - Geoprocessing functions for working with PostGRESQL/ PostGIS layers
SPIT - Shapefile to PostgreSQL/ PostGIS Import Tool
ScaleBar - Draws a scale bar



WFS plugin - Adds WFS layers to the QGIS canvas
Finally "Quantum GIS (QGIS) is a user friendly Open Source Geographic Information System (GIS) that runs on Linux, Unix, Mac OSX, and Windows. QGIS supports vector, raster, and database formats. QGIS is licensed under the GNU General Public License. QGIS lets you browse and create map data on your computer. It supports many common spatial data formats (e.g. ESRI ShapeFile, geotiff). QGIS supports plugins to do things like display tracks from your GPS. QGIS is Open Source software and its free of cost (download here). " (taken from http://www.qgis.org/)

Switching between the ArcGIS Server services in map control with maps on different Co-ordinate Systems using callback (ICallbackHandler)


Today we are going to see how to switch between maps with two different Co-ordinate systems in the map control using ICallbackHandler callback. Please be aware that this code also works for switching the map services in map control with maps in the same co-ordinate systems too.


a. On the page_load create the callbackstring with ProcessCallbackResult as your callback handling function on clientside.

m_page = m_map.Page;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
m_callbackInvocation = m_page.ClientScript.GetCallbackEventReference(m_page, "message", "processCallbackResult", "context", true);
sb.Append("
\n");
if (!m_page.ClientScript.IsClientScriptBlockRegistered("SwitchScript"))
m_page.ClientScript.RegisterClientScriptBlock(m_page.GetType(), "SwitchScript", sb.ToString());

b. You may use a drop down list or button to initiate the map change. If you are using button to initiate the switch between map services initialize the client side onClick event of the button to button1.onClick = "eval(switchCallbackFunctionString);"


c. Your RaiseCallbackEvent function in your cod behind should look like below


void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
{

if(eventArgument =="switchservices")
{

MapResourceManager MapResourceManager1 = Map1.MapResourceManagerInstance;

//MapResourceManager1.ResourceItems.Clear();
MapResourceItem mapResourceItemAreal = new MapResourceItem();
GISResourceItemDefinition definition = new GISResourceItemDefinition();
mapResourceItemAreal.Name = "GREEN";
definition.DataSourceDefinition = "localhost";
definition.DataSourceType = "ArcGIS Server Local";
definition.ResourceDefinition = "(default)@GREEN";
definition.DataSourceShared = true;
mapResourceItemAreal.Parent = MapResourceManager1;
mapResourceItemAreal.Definition = definition;
DisplaySettings displaySettings = new DisplaySettings();
displaySettings.DisplayInTableOfContents = true;
displaySettings.Visible = true;
mapResourceItemAreal.DisplaySettings = displaySettings;

MapResourceManager1.ResourceItems.Clear();
MapResourceManager1.ResourceItems.Insert(0, mapResourceItemAreal);
MapResourceManager1.CreateResource(mapResourceItemAreal);

Toc1.Refresh();
foreach( CallbackResult cr in Toc1.CallbackResults)
Map1.CallbackResults.Add(cr);
Map1.PrimaryMapResource = "GREEN";
Map1.InitializeFunctionalities();
MapResourceManager1.Refresh();

Map1.Refresh();

response = Map1.CallbackResults.ToString();


}
}

d. Make sure you implment GetCallbackResult() as shown below.

string ICallbackEventHandler.GetCallbackResult()
{
return RaiseCallbackEvent(_callbackArg);
}



Some times your might see the TOC getting updated correctly but map control shows blank white screen. In that case set the map initial extent to default map extent of the new map service on the client side. You can click on the zoomtofullextent control to see if it is a problem with the initial extent.

Dynamically change layer symbology in ArcGIS Server MapResourceLocal resource

Today we are going to see how to dynamically change symbology of a lFeature layer in a map with ArcGIS Server MapResourceLocal resource and refresh map control and TOC to display the changes on fly.

ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality agsMapFunctionality =
(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality)Map1.GetFunctionality(0);
m_AGSLocalMapResource = (ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal)

agsMapFunctionality.Resource;
MapServer mapServer = (MapServer)m_AGSLocalMapResource.MapServer;
IMapServerObjects mapServerObject = (IMapServerObjects)mapServer;
string mapName = mapServer.get_MapName(0);
ILayer iLayer = mapServerObject.get_Layer(mapName, 0);
FeatureLayer featureLayer = (FeatureLayer)iLayer;
IFeatureClass featureClass = featureLayer.FeatureClass;
IGeoFeatureLayer geoFeatureLayer = (IGeoFeatureLayer)featureLayer;
IServerContext serverContext = m_AGSLocalMapResource.ServerContextInfo.ServerContext;
ISimpleRenderer simpleRenderer = (ISimpleRenderer)mapContext.CreateObject

("esriCarto.SimpleRenderer");
IRgbColor rgbColor = (IRgbColor)mapContext.CreateObject("esriDisplay.RgbColor");
rgbColor.Red = 20;
rgbColor.Green = 100;
rgbColor.Blue = 210;
ESRI.ArcGIS.Geometry.esriGeometryType geometryType = featureLayer.FeatureClass.ShapeType;
if (geometryType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint)
{
ISimpleMarkerSymbol symbol = (ISimpleMarkerSymbol)mapContext.CreateObject("esriDisplay.SimpleMarkerSymbol");
symbol.Color = (IColor)rgbColor;
simpleRenderer.Symbol = (ISymbol)symbol;
}
else if (geometryType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline)
{
ISimpleLineSymbol symbol = (ISimpleLineSymbol)mapContext.CreateObject("esriDisplay.SimpleLineSymbol");
symbol.Color = (IColor)rgbColor;
simpleRenderer.Symbol = (ISymbol)symbol;
}
else if (geometryType == ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon)
{
ISimpleFillSymbol symbol = (ISimpleFillSymbol)mapContext.CreateObject("esriDisplay.SimpleFillSymbol");
symbol.Color = (IColor)rgbColor;
simpleRenderer.Symbol = (ISymbol)symbol;
}
else
{
throw new Exception("No renderer or symbol selected. Shape type undetermined.");
}
geoFeatureLayer.Renderer = (IFeatureRenderer)simpleRenderer;


if (initialcallback)
{
Toc1.Refresh();
Map1.CallbackResults.CopyFrom(Toc1.CallbackResults);
Map1.Refresh();
m_CallbackResponse = Map1.CallbackResults.ToString();
}




Above code uses a non-pooled server object. In a non-pooled object we will not be sharing the object with another users so we can make any changes to the layer's symbology in the server context but the object will be disposed once we are done using it. Please make sure you release the servercontext in the end.


You've to be little careful when you are using a pooled object especially when you are making stateful changes to it (in this case dynamic symobology) because you will be sharing the same object with others. To avoid any discrepencies when you are done with applying the new symbology to the layer and relflect the changes in all the webcontrols, undo all the changes you have made to the layer and return the object back to the state it was when you got it and then return it back to the pool.

Please feel free to post if you have any suggesions or comments.

Re-writing VBA code to C# for creating polyline shape file directly X,Y co-ordinates in a dbf table.

Writing the code in C# involve quite a few changes from the way it’s written in VBA, especially if you are new to C# world and trying to rewite VBA script into C# code. How FieldCount (IFieldsEdit), AddSegment (ISegmentCollection), AddGeometry (IGeometryCollection), setValue (IFeature) from same interface are implemented different in different languages.


These are the chunks of code that are approached differently in both the languages. The entire code is provided as an attachment.


The way FieldCount is set for interface IFieldsEdit.


1. VBA: variable = object.FieldCount

C#: public int FieldCount {get; }


Example
VBA: Set pFields = New Fields
Set pFieldsEdit = pFields
pFieldsEdit.FieldCount = 3

C#: pFields = new FieldsClass();
pFieldsEdit = (IFieldsEdit)pFields;
pFieldsEdit.FieldCount_2 = 3;

2. Set two a attribute fields by cloning from existing table (IClone)

VBA: Dim pClone As IClone
Set pClone = pTable.Fields.Field(l_A1)
Set pFieldsEdit.Field(1) = pClone.Clone
Set pClone = pTable.Fields.Field(l_A2)
Set pFieldsEdit.Field(2) = pClone.Clone

C#: IClone pClone;
pClone = (IClone)pTable.Fields.get_Field(l_A1);
pFieldsEdit.set_Field(1,(IField)pClone.Clone());
pClone = (IClone)pTable.Fields.get_Field(l_A2);
pFieldsEdit.set_Field(2, (IField)pClone.Clone());

Here the setting of field has taken 2 parameters


3. ISegmentCollection


VBA: Set pLine = CreateLn(CreatePt(pRow.Value(l_X1), pRow.Value(l_Y1)), CreatePt(pRow.Value(l_X2), pRow.Value(l_Y2)))
Set pLine = CreateLn(pFromPoint, pToPoint)
Set pSegColl = New Path
pSegColl.AddSegment pLine
Set pGeomColl = New Polyline
pGeomColl.AddGeometry pSegColl
Set pFeat = pFeatClass.CreateFeature
Set pPolyline = pGeomColl


C#: pLine = CreateLn(pFromPoint, pToPoint);
pSegColl = new PathClass();
object Missing = Type.Missing;
pSegColl.AddSegment((ISegment)pLine, ref Missing , ref Missing);
pGeomColl = new PolylineClass();
pGeomColl.AddGeometry((IGeometry)pSegColl, ref Missing, ref Missing);
pFeat = pFeatClass.CreateFeature();
pPolyline = (IPolyline)pGeomColl;


Here both AddSegment and AdGeometry take 3 parameters and the object has been set as Type.Missing

4. Set the Feature's Shape and the specified attributes


VBA: Set pFeat.Shape = pPolyline
pFeat.Value(l_FCA1) = pRow.Value(l_A1)
pFeat.Value(l_FCA2) = pRow.Value(l_A2)

C#: pFeat.Shape = pPolyline;
pFeat.set_Value(l_FCA1, pRow.get_Value(l_A1));
pFeat.set_Value(l_FCA2, pRow.get_Value(l_A2));

In VBA row vales are read in feature value by equating whereas in C# the values are set with index and the object parameter.

C# to create polyline using the X,Y values from DBF Table

//Create polyline shape file directly from the table between two X and Y
private void CreatePolyLines()
{
string m_sX1 = "X";
string m_sY1 = "Y";
string m_sX2 = "X";
string m_sY2 = "Y";

string m_sAttrib1 = "XYZ";
string m_sAttrib2 = "ID";

IWorkspaceFactory pFact;
IWorkspace pWorkspace;
IFeatureWorkspace pFeatws;
ITable pTable;
pFact = new ShapefileWorkspaceFactoryClass();
pWorkspace = pFact.OpenFromFile(@"pointtoapath", 0);
pFeatws = (IFeatureWorkspace)pWorkspace;
pTable = pFeatws.OpenTable("TableName");



// Find Fields containing X and Y coordinates, and the specified attributes.
int l_X1, l_Y1, l_X2, l_Y2, l_A1, l_A2;
l_X1 = pTable.FindField(m_sX1);
l_Y1 = pTable.FindField(m_sY1);
l_X2 = pTable.FindField(m_sX2);
l_Y2 = pTable.FindField(m_sY2);
l_A1 = pTable.FindField(m_sAttrib1);
l_A2 = pTable.FindField(m_sAttrib2);


// Set up a Fields collection for the new Feature Class.
IFieldEdit pField , pFieldEdit;
IFieldsEdit pFields, pFieldsEdit;
IGeometryDefEdit pGeomDefEdit;
ISpatialReference pSR;

pFields = new FieldsClass();
pFieldsEdit = (IFieldsEdit)pFields;
pFieldsEdit.FieldCount_2 = 3;

// Create the geometry field.
pGeomDefEdit = new GeometryDefClass();
pSR = new UnknownCoordinateSystemClass();
pGeomDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolygon;
pGeomDefEdit.HasM_2 = false;
pGeomDefEdit.HasZ_2 = false;
pGeomDefEdit.SpatialReference_2 = pSR;


pFieldEdit = new FieldClass();

pFieldEdit.Name_2 = "Shape";
pFieldEdit.AliasName_2 = "Geometry";
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;
pFieldEdit.GeometryDef_2 = pGeomDefEdit;

//pFieldsEdit.Field(0) = pFieldEdit;
pFieldsEdit.set_Field(0, pFieldEdit);


// ' Set the two attribute Fields by cloning from the existing Table.
IClone pClone;
pClone = (IClone)pTable.Fields.get_Field(l_A1);
pFieldsEdit.set_Field(1,(IField)pClone.Clone());
pClone = (IClone)pTable.Fields.get_Field(l_A2);
pFieldsEdit.set_Field(2, (IField)pClone.Clone());

// Now create the new Shapefile. First create a Feature UID.
UID pCLSID;
pCLSID = new UIDClass ();
pCLSID.Value = "esricore.Feature";


IFeatureClass pFeatClass;
IWorkspace pWksp;
IFeatureWorkspace pFeatWksp;
IWorkspaceFactory pWkspFact;
pWkspFact = new ShapefileWorkspaceFactoryClass();
pFeatWksp = (IFeatureWorkspace)pWkspFact.OpenFromFile(@"path", 0);
pFeatClass = pFeatWksp.CreateFeatureClass("NameoftheFCtobecreated", pFields, pCLSID, null, esriFeatureType.esriFTSimple, "Shape", "");

// Now, create the Line data and add it to the new FeatureClass along with the
// specified attributes.

// If pFeatClass Is Nothing Then Exit Sub
int l_FCA1 , l_FCA2;
l_FCA1 = pFeatClass.FindField(m_sAttrib1);
l_FCA2 = pFeatClass.FindField(m_sAttrib2);


//Iterate all the rows in the selected Table.
ICursor pTableCursor ;
IRow pRow;
pTableCursor = pTable.Search(null, true);
//If pTableCursor Is Nothing Then Exit Sub
pRow = pTableCursor.NextRow();


IGeometryCollection pGeomColl;
ISegmentCollection pSegColl;
ILine pLine;
IPolyline pPolyline;
IFeature pFeat;
IPoint pFromPoint, pToPoint;

pTableCursor = pTable.Search(null, true);
//If pTableCursor Is Nothing Then Exit Sub
double X1, Y1, X2, Y2;
pRow = pTableCursor.NextRow();


//Do While Not pRow Is Nothing
while (pRow != null)
{
pFeat = pFeatClass.CreateFeature();
pFeat.set_Value(l_FCA1, pRow.get_Value(l_A1));
pFeat.set_Value(l_FCA2, pRow.get_Value(l_A2));

X1 = Convert.ToDouble(pRow.get_Value(l_X1));
Y1 = Convert.ToDouble(pRow.get_Value(l_Y1));

pRow = pTableCursor.NextRow();

X2 = Convert.ToDouble(pRow.get_Value(l_X1));
Y2 = Convert.ToDouble(pRow.get_Value(l_Y1));

pFromPoint = new PointClass();
pFromPoint.PutCoords(X1, Y1);

pToPoint = new PointClass();
pToPoint.PutCoords(X2, Y2);


//For each row in the Table, create a PolyLine.
pLine = CreateLn(pFromPoint, pToPoint);
pSegColl = new PathClass();
object Missing = Type.Missing;
pSegColl.AddSegment((ISegment)pLine, ref Missing , ref Missing);
pGeomColl = new PolylineClass();
pGeomColl.AddGeometry((IGeometry)pSegColl, ref Missing, ref Missing);
pFeat = pFeatClass.CreateFeature();
pPolyline = (IPolyline)pGeomColl;

//Set the Feature's Shape and the specified attributes.
pFeat.Shape = pPolyline;
pFeat.set_Value(l_FCA1, pRow.get_Value(l_A1));
pFeat.set_Value(l_FCA2, pRow.get_Value(l_A2));
pFeat.Store();

pRow = pTableCursor.NextRow();
}
}


Author of this article : Saud Ahmad, GIS Consultant, Houston,

Saud Ahmad is currently working as a GIS Consultant in a houston based GIS IT services company. He has been working in the GIS Industry for over six years with a lot of experience in ESRI based products. He has worked on projects with wide variety of clients in Oil and Gas industry , public works and state government agencies.

Zoom to datatable returned by applying spatialfilter to IQueryFunctionality

Below code sample explains how to zoom to the data returned by querying the map resource by applying spatialfilter to IQueryFuntionality. I tested this method for geometries of type 'Point' and its working. All you have to do is convert the data table returned by the IQueryFunctionality into a graphicslayer and change the map extent to graphicslayer's fullextent.
I also explained another way of doing it by adding the points to the pointcollection and setting the map extent to envelope i.e


ESRI.ArcGIS.ADF.Web.Geometry.Envelope envelope = ESRI.ArcGIS.ADF.Web.Geometry.Envelope.GetMinimumEnclosingEnvelope(pointcollection);


If you are just trying to zoom in to a single feature then the way to do is by setting the map to extent to the geometry's minimum enclosing envelope i.e


ESRI.ArcGIS.ADF.Web.Geometry.Envelope envelope = ESRI.ArcGIS.ADF.Web.Geometry.Envelope.GetMinimumEnclosingEnvelope(geometry);



                                                                                                                      Fig1: Zoom to datatable by IQueryFunctionality


P.S. For structured code sample please leave a comment with your email.
int resourceIndex = 0;
System.Data.DataTable datatable = null;
ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality mf = (ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality)Map1.GetFunctionality(resourceIndex);
ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisresource = mf.Resource;
bool supported = gisresource.SupportsFunctionality(typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality));
if (supported)
{
ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality qfunc;
qfunc = (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)gisresource.CreateFunctionality(typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null);
string[] lids;
string[] lnames;
qfunc.GetQueryableLayers(null, out lids, out lnames);
ESRI.ArcGIS.ADF.Web.SpatialFilter spatialfilter = new ESRI.ArcGIS.ADF.Web.SpatialFilter();
spatialfilter.ReturnADFGeometries = false;
spatialfilter.MaxRecords = 1000;
spatialfilter.WhereClause = "OBJECTID = 5194";
datatable = qfunc.Query(null, lids[0], spatialfilter);
}
ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer graphicslayer = ESRI.ArcGIS.ADF.Web.Converter.ToGraphicsLayer(datatable, System.Drawing.Color.Yellow, System.Drawing.Color.Green);
Map1.Extent = graphicslayer.FullExtent;
Map1.Refresh();
response = Map1.CallbackResults.ToString();
// Another Way to do it
//DataRowCollection dataRowCollection = datatable.Rows;
//ESRI.ArcGIS.ADF.Web.Geometry.Geometry geometry;
//ESRI.ArcGIS.ADF.Web.Geometry.PointCollection pointCollection = new PointCollection();
// for (int i = 0; i < dr =" datatable.Rows[i];" geometry =" dr[20]" env =" ESRI.ArcGIS.ADF.Web.Geometry.Envelope.GetMinimumEnclosingEnvelope(pointCollection);" extent =" env;">