Best Practices: Map Interaction
When you are writing a tool that requires mouse interaction, use the Draw surface instead of listening for mouse clicks. With the Draw surface, you can easily capture geometries that are drawn by users of your application. Once you retrieve these geometries, you can add them to a Graphics layer or use them as input for other operations.
When you are writing a tool that captures map clicks, do the following:
- Use the Draw object to capture mouse input. Keep in mind that there may be other tools in the current Viewer application that also capture map clicks. For this reason, you should always use the Draw object, rather than listening to the Map’s MouseClick event directly, because only one Draw object can be active at a time. If one Draw object is activated while another Draw object is already active, the second Draw object will be automatically deactivated.
- Listen for changes on the Draw object’s IsEnabled property to handle cases where your tool’s Draw object has been automatically deactivated. For example, if you implement an identify tool where you have an active Draw object to capture map clicks and a dialog to show identify results, you would probably want the dialog to close when another tool that captures map input is selected. To do this requires listening for changes to the IsEnabled property.
The code snippets below creates a new Draw surface on the map and sets the DrawMode to Point.
private Identify identifyDialog;
private IdentifyTask identifyTask;
private Draw draw;
public void Execute(object parameter)
{
if (draw == null)
{
draw = new Draw(MapApplication.Current.Map) { DrawMode = ESRI.ArcGIS.Client.DrawMode.Point };
draw.DrawComplete += DrawComplete;
// Listen to the IsEnabled property. This is to detect cases where other tools have
// disabled the Draw surface.
// Utils class shown below.
Utils.RegisterForNotification("IsEnabled", draw, identifyDialog, OnDrawEnabledChanged);
}
draw.IsEnabled = true;
MapApplication.Current.ShowWindow("Identify", identifyDialog, false, null, IdentifyDialogHidden);
}
// Fires when the drawing action is complete. Issues an identify operation using the drawn geometry.
private void DrawComplete(object sender, DrawEventArgs e)
{
MapPoint clickPoint = e.Geometry as MapPoint;
IdentifyParameters identifyParams = new IdentifyParameters()
{
Geometry = clickPoint,
MapExtent = MapApplication.Current.Map.Extent,
LayerOption = LayerOption.visible,
SpatialReference = MapApplication.Current.Map.SpatialReference
};
if (identifyTask.IsBusy)
identifyTask.CancelAsync();
identifyTask.ExecuteAsync(identifyParams);
GraphicsLayer graphicsLayer = MapApplication.Current.Map.Layers["IdentifyResultsLayer"] as GraphicsLayer;
if (graphicsLayer == null)
{
graphicsLayer = createResultsLayer();
MapApplication.Current.Map.Layers.Add(graphicsLayer);
}
else
{
graphicsLayer.ClearGraphics();
}
Graphic graphic = new Graphic() { Geometry = clickPoint };
graphicsLayer.Graphics.Add(graphic);
}
public class Utils
{
public static void RegisterForNotification(string propertyName, object source, FrameworkElement element,
PropertyChangedCallback callback)
{
//Bind to a depedency property
Binding b = new Binding(propertyName) { Source = source };
var prop = System.Windows.DependencyProperty.RegisterAttached(
"ListenAttached" + propertyName,
typeof(object),
typeof(UserControl),
new PropertyMetadata(callback));
element.SetBinding(prop, b);
}
}
8/12/2011