Howard,
I don't really see how it will ever be possible to do searches on shape files on the Client side. This is because most customers have large shape files with a lot of data. If these shape files are in the Xap package, it will be too big. Therefore, it only really makes sense to keep the shape files on the server. Please correct me if I have misunderstood something here. However, in my opinion, the client side application should eventually have functionality to send a search to a server, and have the results returned (e.g. through WMS, or SilverlightMapConnector).
Here is my sample code for searching within a radius. Bare in mind it returns a list of Assets which is our custom class. The search gets the COMPKEY of the records in the shape file but people can alter this code to suit their own needs. This is a WCF service OperationContract which can be called from within Silverlight. You can call it from the Map's Click event using the X,Y coords.
[OperationContract]
public List<Asset> GetAssetsWithinDistanceOf(double x, double y, double searchRadius)
{
//Get controls
var layerDictionary = new Dictionary<string, Collection<Feature>>();
var retVal = new List<Asset>();
//Iterate through layers
foreach (ShapeFileFeatureLayer layer in ShapeFileFeatureLayerProvider.Layers.Values)
{
layer.Open();
if (layer.QueryTools != null)
{
//Get columns in layer
var columns = layer.QueryTools.GetColumns();
//Add column names to a list
var columnNames = new List<string>();
foreach (var column in columns)
{
columnNames.Add(column.ColumnName);
}
//Query the layer for features within one meter of point clicked
string columnNamesString = string.Join(",", columnNames.ToArray());
var pointString = string.Format("X: {0}\tY: {1}", x, y);
try
{
var pointShape = new PointShape(x, y);
var features = layer.QueryTools.GetFeaturesWithinDistanceOf(pointShape, GeographyUnit.Meter, DistanceUnit.Meter, searchRadius, columnNames);
//Add features to dictionary
layerDictionary.Add(layer.Name, features);
}
catch (Exception ex)
{
Logger.Log(string.Format("Error occurred when calling GetFeaturesWithinDistanceOf().\r\nLayer: {0}\r\nTarget Shape: {1}\r\nDistance: {2}\r\nReturning Column Names: {3}\r\nError:\r\n{4}", layer.Name, pointString, searchRadius, columnNamesString, ex.ToString()), Logger.MessageType.Error, this.GetType().FullName, true);
layer.Close();
throw ex;
}
}
layer.Close();
}
//Clear the assetlistbox items
retVal.Clear();
//Iterate through layers
foreach (var layerName in layerDictionary.Keys)
{
//Iterate through each selected feature in the layer
foreach (var selectedFeature in layerDictionary[layerName])
{
//Check that there is a COMPKEY and UNITID
if (
selectedFeature.ColumnValues.ContainsKey("COMPKEY") &&
!selectedFeature.ColumnValues["COMPKEY"].Equals(DBNull.Value) &&
selectedFeature.ColumnValues.ContainsKey("UNITID") &&
!selectedFeature.ColumnValues["UNITID"].Equals(DBNull.Value) &&
!string.IsNullOrEmpty(selectedFeature.ColumnValues["UNITID"]) &&
!string.IsNullOrEmpty(selectedFeature.ColumnValues["COMPKEY"])
)
{
//Remove decimal places if necessary
var gisKeyString = (string)selectedFeature.ColumnValues["COMPKEY"];
if (gisKeyString.IndexOf('.') != -1)
{
gisKeyString = gisKeyString.Split(new char[] { '.' })[0];
}
var asset = BusinessAccessLayer<Asset>.GetRecord(Asset.ColumnGISKey, gisKeyString, null);
retVal.Add(asset);
}
}
}
return retVal;
}
Christian