From Bryan Baker, a product engineer working on the .NET SDK:
I wrote an earlier post that showed how to extend the QueryAttributes task so that all features are immediately highlighted. Several users have asked about also zooming to the selected features. I'll show that here, though keep in mind that the user can also zoom to the selected features by right-clicking on the node for the layer (Cities in the graphic at the top of the earlier post) and choosing to zoom to selected features.
It turns out that it's a little more difficult to zoom to the features than I originally thought, because the FullExtent property of the graphics layer is null for queries like this. Instead, we have to construct our own envelope around all the features by looping through them. This isn't that difficult, though of course it does require more processing.
I’ve included code below that does the zooming. This code should be added to near the bottom of the existing code in the earlier post. If for some reason you didn’t want to highlight all the features, you could omit or comment out the line in the loop that sets the selectedCol to true.
The code below first creates an envelope to use, then in the existing loop that selects each feature, it widens the envelope to surround each feature. Once it has the envelope, it gets a reference to the Map control so it can set the Map’s extent. This takes some work, since the task itself has no reference to the Map. We have to get the ID of the Map and then search the page’s control tree. Since the Map control could be nested within another control, such as in a FloatingPanel, we search for it recursively using a custom function (found at the bottom of this listing).
One more thing before we zoom the map: the task could be querying a point layer, and if only one point is found, the “envelope” around all features is a point. We can’t zoom to a point, so instead we set the envelope to a percentage of the full extent of the Map (five percent—this value is hard-coded here, and you can change it depending on tightly you want to zoom in this one-point case).
Finally, we’ve got an envelope that will work, and we set the Map to this extent, refresh the Map, and copy its CallbackResults to the task’s CallbackResults. This last step is necessary because a callback only works with one control (the task in this case), and we need to tell another control (the Map) to update its contents.
' Set up the items to hold the extent of all features
Dim geom As ESRI.ArcGIS.ADF.Web.Geometry.Geometry
Dim layerEnv As New _
Double.MaxValue, Double.MaxValue, _
' Set each feature to selected (this loop is
' at the end the code in my previous blog post)
For Each row As DataRow In graphicsLayer.Rows
row(selectedCol) = True
' Enlarge the overall envelope to
' include the current feature
geom = graphicsLayer.GeometryFromRow(row)
' If any records found, zoom to them
If graphicsLayer.Rows.Count > 0 Then
' Get a reference to the Map – have to search the Page since
' task itself has no direct reference to the Map
' (the task's TaskResults does have the ID of the map)
Dim mapCtrl As Map = Nothing
Dim taskResultsId As String =
Dim taskResults As TaskResults = _
Me.Page, taskResultsId), TaskResults)
If Not TaskResults Is Nothing Then
mapCtrl = CType(FindControlRecursive( _
Me.Page, taskResults.Map), Map)
If Not mapCtrl Is Nothing Then
' If only one point found, envelope will be a point
' – set to a percentage of the full extent
If layerEnv.XMin = layerEnv.XMax AndAlso _
layerEnv.YMin = layerEnv.YMax AndAlso _
Not IsNothing(mapCtrl) Then
' Percentage of the full extent to use when zooming to point
Dim zoomToPointPercentage As Integer = 5
Dim NewWidth As Double = mapCtrl.GetFullExtent().Width _
* (zoomToPointPercentage / 100)
Dim NewHeight As Double = mapCtrl.GetFullExtent().Height _
* (zoomToPointPercentage / 100)
layerEnv.XMin -= NewWidth / 2
layerEnv.XMax += NewWidth / 2
layerEnv.YMin -= NewHeight / 2
layerEnv.YMax += NewHeight / 2
' Now we can zoom the map to the extent of the features
mapCtrl.Extent = layerEnv
' We have to tell the client to refresh, using CallbackResults
Below is the function called in the above code. This searches the page and its child controls for the control with the given ID. Put this after the end of the Execute method (End Sub), but inside the Class (before the End Class statement).
' Finds the control in the Page's control tree
Public Function FindControlRecursive(ByVal root As _
Control, ByVal id As String) As Control
If root.ID = id Then
Dim c As Control
For Each c In root.Controls
Dim t As Control = FindControlRecursive(c, id)
If Not t Is Nothing Then
If you add the code above to the custom task as outlined in the earlier blog post, it should automatically zoom to the extent of all features found by the task.