How to select feature by attribute?

I've been trying to wrap my head around SharpMap v0.9. I'm trying to incorporate it into a .Net 2.0 WinForms application using Visual Studio 2005 Pro.

What I haven't been able to fathom is how to select a feature based on an attribute.

I would like the user to enter a string and search the displayed layer for any records that match that value in a particular attribute. Currently I am using shape files. So far, the only thing I can come up with is to loop through the entire
layer checking every record for ones that match the query string.

Is there a better way to do this (I hope)?

I was looking for something like a .Find(<SQL Where Predicate>) that would return a feature data table.

I've attempted to select a single polygon in a shape file and display the selected polygon using a FilterDelegate Unfortunately I don't get anything to draw on the map. Below is the code for event of a button that takes the text the user enters
and tried to find the matching polygon.

I've based it on your previous posting;

"Hi siddhesh123, you dont need to executeintersectionquery yourself unles you are trying to get the data for soe non rendering purpose..

I don't know how addicted you are to Shapefiles. If you could consider a different provider
(e.g. PostgreSql/Postgis, SqlServer2008, SpatiaLite, ...) you can use the DefinitionQuery
property which adds an optional where clause to the spatial select command.

Another possibility might be the use of the Select(...) command of the FeatureDataTable class.
True intersection test with NTS would look like this:

public FeatureDataTable GetIntersectingFeaturesUsingFilterDelegate(string pathToShapefile, Geometry testGeometry)
{
//create a new shapefile provider using (ShapeFile shapefile = new ShapeFile(pathToShapefile))
{
//create an nts GeometryFactory
GeometryFactory geometryFactory = new GeometryFactory();
//convert the testGeometry into the equivalent NTS geometry
GisSharpBlog.NetTopologySuite.Geometries.Geometry testGeometryAsNtsGeom =
GeometryConverter.ToNTSGeometry(testGeometry, geometryFactory);
//set the shapefile providers' FilterDelegate property to a new anonymous method//this delegate method will be called for each potential row
shapefile.FilterDelegate = delegate(FeatureDataRow featureDataRow)
{
//get the geometry from the featureDataRow
Geometry rowGeometry = featureDataRow.Geometry;
//convert it to the equivalent NTS geometry
GisSharpBlog.NetTopologySuite.Geometries.Geometry
compareGeometryAsNtsGeometry =
GeometryConverter.ToNTSGeometry(rowGeometry,
geometryFactory);
//do the test. Note that the testGeometryAsNtsGeometry is available here because it is //declared in the same scope as the anonymous method.bool intersects =
testGeometryAsNtsGeom.Intersects(compareGeometryAsNtsGeometry);
//return the resultreturn intersects;
};
//create a new FeatureDataSet
FeatureDataSet featureDataSet = new FeatureDataSet();
//open the shapefile
shapefile.Open();
//call ExecuteIntersectionQuery. The FilterDelegate will be used to limit the result set
shapefile.ExecuteIntersectionQuery(testGeometry, featureDataSet);
//close the shapefile
shapefile.Close();
//return the populated FeatureDataTable
FeatureDataTable fdt = featureDataSet.Tables[0];
FeatureDataTable fdtSelect = fdt.Clone();
fdtSelect.BeginLoadData();
foreach (DataRow row in fdt.Select("NUM=1"))
fdtSelect.ImportRow(row);
fdtSelect.EndLoadData();
return fdtSelect;
}
}

Thanks for the suggestion. Your code looks nice. What I am interested in though is pure non-spatial queries. Apparently SharpMap v0.9 (with your help I'm using 0.9.3691.27741) can't actually do a non-spatial query. There doesn't seem
to be a way to get the FilterDelegate to actual run unless it's part of the ExecuteIntersectionQuery, what would be nice would be an ExecuteQuery method. To make matters even more frustrating, it doesn't look like there's a way to access the 'live' FeatureDataTable
of a displayed layer in any significant way. You can't take an existing layer and select one or more geometries, even if it's a spatial query (ExecuteIntersectionQuery) within that layer. You need to create yet another layer for every selection
set. SharpMap layers are apparently very, painfully, static. I've written code so that every time the user does a selection (spatial or not) I delete the previous layer and replace it with the current selection. Being as this is .Net code
and that the FeatureDataSet inherits from the DataSet (I assume) I would have expected to be able to utilize at least some of the underlying ADO.Net query capabilities. Unfortunately I get the feeling that even if I could, the only time I would be able
to do anything with it would be at creation. Oh well, perhaps v2.0 will be more dynamic.

As for shape files, the project I am working on at the moment will allow the user to edit a large quantity of non-spatial data in a series of related tables. The only spatial component is to allow the users the ability to optionally see the location
of the data they are editing (hence the need for a non-spatial query - to sync the display to the record the user is currently editing) or review/edit the data of a location that they select spatially. The spatial data will be created and maintained
in ESRI's ArcGIS. There is a requirement not to install anything other than the program itself. If SharpMap supported ESRI's personal geodatabase I would have been tempted to use that. Of the options listed here:

Shape file seemed to be the simplest that wouldn't require installing anything on the client's machine.

SpatialLite looks promising, if it can support/load geometry from ESRI and handle the non-spatial data as well, (is it well supported by .Net 2.0) we might have a winner.

When I was looking to support my modest spatial needs, SharpMap looked like an adequate .Net solution. ESRI's licensing costs would have been prohibitive for a small project like this with it's minimalistic spatial requirements.

for plain queries you can certainly use Microsofts OleDb provider to access the dbase file related
to the shapefile in question (see
this). You might even be able to update your data, which you can't otherwise
do with sharpmap v0.9.

SpatiaLite has just recently been added to the project, I can't say how many other people use it. It
is a native library loaded into the SQLite.Net Data provider.

In order to use SpatiaLite with sharpmap, you need to download the windows binaries from
here,
unzip them all to one and the same folder and update the path variable to include that directory.
Then you should be all set to use the provider. There are gui/commandline tools that are capable
of loading shapefiles into spatialite/sqlite databases. As spatialite is an extension to sqlite you
can add non-spatial data to the database as well.

Perhaps you want to join us at the weekly
irc,. It is usually wednesday ~9PM CET.

Thanks for the invite, but that's about 3PM EST (where I'm at) and they don't let us access the IRC from the office. :(

Although that explains why, the few times I've dropped in, no one's been home.

I'm using the native methods (ADO.Net) to edit the non spatial data. In this instance the only attribute the shape file has is a unique key in the form of a long int. I need to non-spatially query the shape file to display/pan/zoom to the correct
geometry. Presently if I query the shape file using ADO.Net I can't have SharpMap select or display the correct geometry, nor can it pan or zoom to the resultant set. SharpMap's map is blissfully ignorant of any ADO.Net operations performed on
the spatial data. Perhaps I've just got an ESRI bias, having worked from Arc/Info -> ArcView 3.x -> MapObjects -> ArcGIS (ArcObjects). I still think it's important for SharpMap to be able to access/reselect/etc. geometry non-spatially
as well as spatially. It would also help if the data wasn't so static. If you could apply a DefQuery or FilterDelegate to a layer already attached to a map and have it update on the next Refresh(). An associated 'IsSelected' bit mask would
be really handy as well. True for currently selected records, false otherwise. Then you could display geometry with whatever renderer for those records whose IsSelected is False and define a separate Selected symbology for those geometries where
IsSelected is True. Just think about how much faster/simpler selecting geometries would be. You would load a layer into your map, the bit mask would be all 0's and so it would draw as defined. You would use either an SQL query, a spatial
query (ExecuteIntersectionQuery, etc.) or both, to select a subset and reset the mask for those values to '1'. On the next refresh '0' draws the same, '1' is drawn highlighted. ZoomToSelected, PanToSelected, etc. would be operations that would
be based on IsSelected = '1'. No need to reload layers from disk. No need to delete layers from the map, only to add the same layer back in. Simple, clean, fast.

Well, perhaps the developers are already working on that in v2.0.

I've taken your advice and started looking at the MapBox as opposed to the MapImage. I'm surprised the default wasn't to build both MapImage and MapBox. It's definitely much faster than the MapImage. Would you have any sample code that
illustrates the use of the MapBox/MapBox tools? The default demos all use the MapImage.