With Silverlight 3.0 we now have a new MouseWheel event on all UIElements. Prior to v3, we had to rely on javascript in the browser to respond to mousewheel events in Silverlight. The problem with this is that there are several cases where the DOM bridge required to execute javascript is disabled. This includes full-screen mode, cross-domain hosting of the .xap file, out-of-browser installs and if the developer explicitly disabled the DOM bridge. Since the Silverlight Map Control is currently built for Silverlight 2.0 (but runs fine with Silverlight3) the user can’t use the mousewheel to zoom in and out when in any of these modes. However, if you build your own application against the Silverlight 3 API, a little bit of custom code can enable the mouse wheel in these cases. This blog post will demonstrate a custom “Behavior” you can attach to your map, which will enable the mousewheel for zoom in these modes.
Behaviors, triggers and actions are new Silverlight 3 features included in an assembly installed with Expression Blend SDK. They allow you to add a lot of functionality to your application using drag’n'drop in Blend, or with some simple XAML in Visual Studio’s XAML editor.
First of all, to create your own custom behaviors, you will need to add a reference to the following assembly: System.Windows.Interactivity.dll. This assembly is usually located in:
“c:\Program Files\Microsoft SDKs\Expression\Blend 3\Interactivity\Libraries\Silverlight\System.Windows.Interactivity.dll”
When the assembly reference is added, download the zip file included with this post, extract the contents to a location of your choice, and add the following file to your project: [WheelZoom.cs]
Next go to your .xaml page that contains your map control, and in the header register the following two namespaces. One for the Interactivity assembly we just added a reference to and the other for the WheelZoom class:
xmlns:i=”clr-namespace:System.Windows.Interactivity;
assembly=System.Windows.Interactivity”
xmlns:behaviors=”clr-namespace:ESRI.ArcGIS.Samples.Behaviors”
Lastly, inside your map control add the following highlighted code:
<esri:Map x:Name=”map”>
<i:Interaction.Behaviors>
<behaviors:WheelZoom />
</i:Interaction.Behaviors>
…
</esri:Map>
That’s it! Now you have mousewheel zoom support when you are in full-screen mode or running your application out of browser.
If you are not interested in the details of how this worked, you can stop here, but personally I think triggers, actions and behaviors are some of the really cool stuff in Silverlight 3.0 that allows you to much better structure, separate and reuse your code.
So how did this work?
First we create a new behavior class that inherits from Behavior<Map>. We specify Map as the generic parameter to signify that this behavior only works with the ESRI map control.
Next there are two methods on the base class that you must override: “OnAttached” and “OnDetaching”. Basically the first method is called when the behavior is added to the map, and the other when it is removed again. So in OnAttached we add an event listener for the MouseWheel event on the map control, and remove it again in OnDetaching:
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.MouseWheel += AssociatedObject_MouseWheel;
}protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.MouseWheel -= AssociatedObject_MouseWheel;
}
The “AssociatedObject” is in this case the Map control that the behavior is attached to.
In the mousewheel event handler we will simply zoom the map around the mouse pointer, using the ZoomToResolution method which allows us to specify a point to zoom about:
private void AssociatedObject_MouseWheel(object sender, MouseWheelEventArgs e)
{
double factor = e.Delta < 1 ?
this.AssociatedObject.ZoomFactor : 1 / this.AssociatedObject.ZoomFactor;
MapPoint center = AssociatedObject.ScreenToMap(e.GetPosition(AssociatedObject));
double res = this.AssociatedObject.Resolution * factor;
this.AssociatedObject.ZoomToResolution(res, center);
}
The code you can download here adds a little extra logic to better match what the javascript-based mousewheel zoom does, but this is the general idea.
To round this off, here’s another type of behavior you can add to your map: [MaintainExtentBehavior.cs]
This behavior will maintain the current extent of the map when the map (browser) is resized. Change to the Silverlight application to display full screen -or- grab a corner of the browser and resize it. The extent of the map will be maintained. Add it in the Interaction.Behaviors collection like we earlier did with the MouseWheel using the following syntax:
<i:Interaction.Behaviors>
<behaviors:WheelZoom />
<behaviors:MaintainExtentBehavior />
</i:Interaction.Behaviors>
The behavior works much the same way, but uses a set of events on the map to store the current extent (ExtentChanging, ExtentChanged) and set the map extent (SizeChanged). If you want to see more examples how also actions and triggers can be used, take a look at the Showcase application in the resource center.
Download a sample from our development server – view the sample live to see it in action.
Morten Nielsen
Senior Software Engineer
ArcGIS Server.NET, Silverlight/WPF, MapIt