• The ArcGIS API for Microsoft Silverlight/WPF version 1.2 is available!

    Version 1.2 of the ArcGIS API for Microsoft Silverlight/WPF is now available for download on the ArcGIS Server Resource Center.    This is a quality release that contains a set of updates and fixes.  It is important to note that you can install multiple versions of the ArcGIS API for Silverlight/WPF on the same machine, but the IDE integration features (assembly references, toolbox integration, and templates) will reference the last installed version.  As a result, if you install 1.2 on a machine that has 1.1, all IDE integration features will reference 1.2.  The 1.1 Silverlight and WPF assemblies will remain installed. 

    Here are a few highlights of what's new:

    • A new event handler has been added to feature layers to listen for updates. The UpdateChanged event will fire when the all graphic features in the feature layer have been retrieved.
    • Spatial reference of geometry returned from DrawCompleted event and query operation matches the map. 
    • Added an Effect property to layers to enable the use of a pixel shader.
    • Navigation control's zoom slider can be enabled by setting minimum and maximum resolution on the map. The zoom slider is no longer dependent on a tiled map service layer to be displayed.
    • The Standard and Showcase Silverlight templates are now integrated with Visual Web Developer Express 2008. 

    We invite you to update to the latest version and continue creating effective, visually stunning Web and desktop applications.    

    Enjoy!

    The ArcGIS Silverlight/WPF Development Team

  • Sending geometry between Silverlight and the server using WCF

    Several posts on our Silverlight and WPF forums contain questions about how to send geometry back and forth between the server and the Silverlight client application. This can be useful when creating a service that stores graphics users want to share with others, loads data from other datasources, or uses ArcObjects to perform custom processing that ArcGIS Server REST services do not expose.

    Most of the current solutions involve creating custom serializers that manually convert geometry into some sort of string format, such as XML or JSON. This works well, but there is a much easier way to do it using Silverlight and WCF's Binary XML support. The fact that our client API includes matching .NET assemblies for both Silverlight and WPF platforms is pivotal to enabling this functionality.  Geometry represented on the client using our Silverlight libraries mirrors geometry represented using our WPF libraries on the server .  Basically, WCF and Silverlight will automatically manage the serialization and transmission of  data, so you do not need to create serializers for the geometry, and you can continue to write type-safe code.

    Follow the steps below to set up a simple WCF based service that the Silverlight API will use to send and receive geometry.  Pay close attention to whether the steps refer to the website project or the Silverlight project.

    Open Visual Studio and select to create a new Silverlight Application project.

    Select "yes" to create a website to host your application:

    Create the WCF service.  Right-click the website project, select "Add reference..." and add a reference to the WPF build of the ESRI.ArcGIS.Client.dll assembly.

    Similarly, right-click the Silverlight project, select "Add reference..." and add a reference to the Silverlight build of the ESRI.ArcGIS.Client.dll assembly.

    Make sure you pair the right assembly with the right project. With these two references added, both the ASP.NET website at the server end as well as the Silverlight client will know how to work with the ESRI.ArcGIS.Client.Geometry namespace. Note that there are some classes in our WPF libraries that require you to add a reference to ‘WindowsBase' in the website application.

    Next, right-click the website project, select "Add a New Item..." and add a "Silverlight-enabled WCF service". This will be the service our Silverlight application will work with.

    When the service was created it generated a default "DoWork" method that takes no arguments and generates not return values.  Change the method so it takes and/or returns an ESRI.ArcGIS.Client.Geometry.* type as parameter. Here's a simple example of a method that takes a point, adds a certain amount to the X and Y, and returns a new shifted point:

     
    [OperationContract]
    public MapPoint Shift(MapPoint point, double amount)
    {
       return new MapPoint(point.X + amount, point.Y + amount);
    }
    
    

    Similarly you can use Polygon and Polyline to send and/or receive geometry between the server and client.  This example is merely instruct.  The business logic in this method could reside in the client, whereas a more purposeful example would involve using logic that solely resides in APIs or functionality only available on the server.  For example, using ArcObjects to perform an advanced geospatial operation.   

    You can add more methods to your service class. Just make sure you prefix each method you want to expose in the service with the [OperationContract] attribute.

    If you right-click the .svc service in the Solution Explorer and select to view it in the browser, you will see something like this:

    Select the URL that is displayed in the browser and copy it. We will use this URL as a service reference in the Silverlight application. Right-click your Silverlight project and select "Add Service Reference...", then paste in the URL you just copied.  Click "Go" and "OK". You should see something like this:

     

    Note: You must add a reference to ESRI.ArcGIS.Client.dll in the Silverlight application before adding the service reference. If you have not, Visual Studio will auto-generate a new set of Geometry classes that are not the same as the ArcGIS Silverlight/WPF Geometry classes.  

    With the service added, we can now start using the service directly inside Silverlight. Here is an example:

     
    ServiceReference1.MyGeometryServiceClient client = new ServiceReference1.MyGeometryServiceClient();
    client.ShiftCompleted += client_ShiftCompleted;
    client.ShiftAsync(new ESRI.ArcGIS.Client.Geometry.MapPoint(10, 10), 0.5);
    
    

    Our ShiftCompleted handler takes an event argument whose Result property will contain the MapPoint instance:

     
    private void client_ShiftCompleted(object sender, SilverlightApplication1.ServiceReference1.ShiftCompletedEventArgs e)
    {
       MapPoint result = e.Result;
    }
    
    

    Note that the method automatically matches the service's arguments to the ESRI.ArcGIS.Client.Geometry.MapPoint type so you don't need to handle any conversion or serialization. 

    If you want to send attributes to the server as well, note that you cannot send a "Graphic" object since this object and its Symbol are not serializable. Instead you can send the geometry back together with the attribute dictionary. For example:

     
    [OperationContract]
    public void SaveFeature(Polygon polygon, Dictionary<string,object> attributes)
    {
       //TODO
    }
    
    

    Alternatively you can create your own class that holds both the geometry and attributes:

     
    [DataContract]
    public class GeometryAndAttributes<
    {
       [DataMember]
       public Dictionary<string, object> Attributes { get; set; }
    
       [DataMember]
       public Geometry Geometry { get; set; }
    }
    
    [OperationContract]
    public IEnumerable<GeometryAndAttributes> GetFeatures()
    {
       //TODO
    }
    
    

     

    Morten Nielsen
    Senior Software Engineer
    ArcGIS Server.NET, Silverlight/WPF, MapIt

  • How to use secure ArcGIS Server services

    The ArcGIS Silverlight/WPF API contains functionality and is built on a platform that enables access to secure ArcGIS Server services. This post will discuss a few basic solutions for working with secure services.  There are two general scenarios which will dictate the options available.  One, as an application developer you need to access secure services but do not want the end user to provide credentials.  In this scenario, use the proxy page approach.  The proxy page included with the Silverlight/WPF SDK is an ASP.NET HTTP handler.  Web requests from a Silverlight or WPF client are redirected through the proxy, which adds credential information.  Credentials can be defined by the proxy administrator for both token and Windows/HTTP secured services.  The end user is often unaware they are using secure services.  You can read about and download the proxy in the secure services discussion included with the SDK.

    In the other scenario, as an application developer you want the end user to provide credentials for secure services.  This will require some extra work in the client application.  Let's start with Windows/HTTP secured services.  First, you will need to create and add Windows/HTTP secured services as layers in code behind.  And second, the ArcGIS Silverlight/WPF API does not provide access to the web request generated by a layer, so credentials cannot be explicitly assigned.  Instead you can use browser logic to associate credentials with a layer's Url.  Start by triggering a credential dialog for the end user to enter a username and password.  Use the WebClient class and the Url of the layer.  An HTTP response code of 401 should be returned, which will trigger the credential dialog.  Once the correct domain\username and password are entered the browser will handle the credentials for you. Here's a quick example to illustrate:

        public partial class MapHttpAuthDemo : UserControl
        {
            public MapHttpAuthDemo()
            {
                InitializeComponent();
    
                ArcGISDynamicMapServiceLayer layer = new ArcGISDynamicMapServiceLayer()
                {
                    Url = "http://myserver/ArcGIS/rest/services/USA_Data/MapServer",
                    ID = "USA"                
                };
    
                layer.InitializationFailed += layer_InitializationFailed;
                AddLayerWithCredentials(layer);
            }
    
            void layer_InitializationFailed(object sender, EventArgs e)
            {}
    
            private void AddLayerWithCredentials(ArcGISDynamicMapServiceLayer layer)
            {
                WebClient challengeRequest = new WebClient();
                challengeRequest.DownloadStringCompleted += (sender, args) =>
                {
                    MyMap.Layers.Add(layer);
                };
    
                challengeRequest.DownloadStringAsync(new Uri(layer.Url));
            }
        }
    

    Note, if end user credentials must be passed in clear text (e.g. basic http authentication) then use https.  Also keep in mind that each Url can be associated with its own credential, however a challenge will be required for each one.

    Next, let's discuss token authenticated services.  In this case the end user will likely provide a username and password in the application UI.  The credentials will be added in a request to an ArcGIS Server token service which will return a token string.  Since the credentials are passed in the Url, in clear text, this request should made over HTTPS.  On response from the token service the token string is assigned to a layer and the layer is added to a map.  Since Silverlight 3 does not support setting the Referer header (supported in Silverlight 4), only short term tokens can be used. The default timeout for a short term token is 60 minutes.  As a consequence, a token may expire during a session.  You can interrogate a response from the token service to listen for an invalid/expired token, or you can keep track of token timeouts on the client using a DispatchTimer to request a token at a predetermined interval.  In any case, once you change the token the layer must be reinitialized.  To force reinitialization, flip the Url property between the original Url and null.  Here's a quick example to illustrate: 

        public partial class MapTokenDemo : UserControl
        {
            string username = "user";
            string password = "pass.word";
            string timeout = "60";
    
            public MapTokenDemo()
            {
                InitializeComponent();
    
                ArcGISDynamicMapServiceLayer layer = new ArcGISDynamicMapServiceLayer()
                {
                    Url = "http://myserver/arcgis/rest/services/USA_Data/MapServer",
                    ID = "USA"                
                };
    
                layer.InitializationFailed += layer_InitializationFailed;
                ConfigureLayerWithToken(layer);
            }
    
            void layer_InitializationFailed(object sender, EventArgs e)
            {}
    
            private void ConfigureLayerWithToken(ArcGISDynamicMapServiceLayer layer)
            {
                string tokenurl =
                    string.Format("https://myserver/arcgis/tokens?request=getToken&username={0}&password={1}&timeout={2}", 
                    username, password, timeout);
    
                WebClient tokenService = new WebClient();
                tokenService.DownloadStringCompleted += (sender, args) =>
                {
                    layer.Token = args.Result;
                    string originalUrl = layer.Url;
                    if (MyMap.Layers.Contains(layer))
                    {
                        layer.Url = null;
                        layer.Url = originalUrl;
                    }
                    else
                        MyMap.Layers.Add(layer);
                };
    
                tokenService.DownloadStringAsync(new Uri(tokenurl));
            }
        }
    

    The code samples presented above are designed to illustrate basic patterns for dealing with secure ArcGIS Server services.  They will likely need to be enhanced to support your specific implementation.

    Enjoy!

    Rex Hansen
    ESRI Product Engineer
    ArcGIS Server .NET, Silverlight/WPF, MapIt

  • Listen for updates to a FeatureLayer

    The ArcGIS Silverlight/WPF API provides a FeatureLayer as an efficient means for referencing a layer that contains features (geometry and attributes) and resides on a server.  You can add a FeatureLayer to a Map in XAML, define the URL to the layer on the server, add symbology and the feature layer contents will be rendered in the Map as graphic features.  Technically the FeatureLayer is a GraphicsLayer that wraps a QueryTask which queries either a feature layer in an ArcGIS Server map service or a spatial table via the MapIt Spatial Data Service. 

    Unfortunately the FeatureLayer does not explicitly expose any events dealing with the query operation, such as when the query has completed and all features have been returned.   This may be necesssary if you need to define renderers on the fly, determine query progress, etc.  To determine when a FeatureLayer query is complete you can listen to the collection changed event on the FeatureLayer.Graphics property.  However this event will be triggered each time a graphic is added, so you need to wait until all graphics have been added.  Enter the Dispatcher class.  Dispatcher enables you to invoke a delegate on the UI (main) thread.  In this case, the completed event on the QueryTask inside the FeatureLayer is executing on the UI thread.  You can call the Dispatcher.BeginInvoke method and delegate a call to code of your choice.  Since this delegate must execute on the UI thread, it must also wait for the completed event on QueryTask to finish before being called.  So in effect, the delegate in BeginInvoke is waiting in a queue.  Also, so the delegate isn't called each time the graphics collection changes, remove the collection changed event handler upon the first call.  You can readd the handler in your code logic if you need to continue listening to changes in a FeatureLayer's graphics collection. A basic code example is provided below.  It assumes a FeatureLayer named "MyFeatureLayer" has been defined in XAML:

    ESRI.ArcGIS.Client.FeatureLayer _featureLayer;
    
    public FeatureLayerEventingDemo()
    {
        InitializeComponent();
    
        _featureLayer = MyMap.Layers["MyFeatureLayer"] as FeatureLayer;
        _featureLayer.Graphics.CollectionChanged += Graphics_CollectionChanged;
    }
    
    void Graphics_CollectionChanged(object sender, 
        System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        // Remove event method on the first call, then invoke delegate
        _featureLayer.Graphics.CollectionChanged -= Graphics_CollectionChanged;
        System.Windows.Application.Current.RootVisual.Dispatcher.BeginInvoke(
    	delegate { 
    	    doSomething(); 
    	});
    }
    
    private void doSomething()
    {
        // Do something... then readd event method to listen for another update
        _featureLayer.Graphics.CollectionChanged += Graphics_CollectionChanged;
    }

    Rex Hansen
    ESRI Product Engineer
    ArcGIS Server .NET, Silverlight/WPF, MapIt

     

  • Sort query results using LINQ

    Sorting data on values in a column is a common requirement in many applications.  Whether defining a more intuitive presentation of information  or merely providing a more aesthetic user experience, an organized presentation of attribute data is ideal. Unfortunately many data sources used by the Silverlight/WPF API do not inherently support ordering query results, or provide limited support.  For example, queries against layers in ArcGIS Server services will only support ORDER BY if hosted in ArcSDE.  Even if supported by the layer, the REST API does not expose the ability to add the ORDER BY clause.  Note that it is supported in the SOAP API using the QueryFilter.PostfixClause property.  For SQL Server tables hosted as layers via the MapIt Spatial Data Service, ordered data can be provided in a view which must be created beforehand.  The Spatial Data Service does not support ordering on the fly.  In either case, sorting query results cannot be done in a service request so the sorting operation is left up to the client.  In Silverlight/WPF querying layer contents usually involves the QueryTask which returns a FeatureSet (IEnumerable<Graphic>).  While there are a few techniques for sorting data in Silverlight, LINQ provides an quick and easy solution.  Here's an example which queries a layer in an ArcGIS Server map service and uses LINQ to sort results in ascending order using the NAME field:

    public void SortGraphicsDemo()
    {    
        QueryTask queryTask = 
          new QueryTask("http://services.arcgisonline.com/ArcGIS/rest/services"
                        + "/Demographics/USA_Population_Density/MapServer/4");
        Query query = new Query();
        query.Where = "1 = 1";
        query.OutFields.Add("*");
    
        queryTask.ExecuteCompleted += queryTask_ExecuteCompleted;
        queryTask.ExecuteAsync(query);
    }
    
    void queryTask_ExecuteCompleted(object sender, QueryEventArgs e)
    {
        var enumGraphics = from g in e.FeatureSet
                           orderby (g.Attributes["NAME"] as string) ascending
                           select g;
    				  
        foreach (ESRI.ArcGIS.Client.Graphic gn in enumGraphics)
        {
            System.Diagnostics.Debug.WriteLine
    	(string.Format("{0},{1}", gn.Attributes["NAME"], gn.Attributes["TOTPOP_CY"]));
        }
    }  

    Rex Hansen
    ESRI Product Engineer
    ArcGIS Server .NET, Silverlight/WPF, MapIt

     

  • Deploy an ArcGIS Silverlight application to Windows Azure

    At the end of 2008, Microsoft unveiled the Windows Azure platform as a set of cloud computing services which provide hosted operating system, database, web application, and security solutions.  For the past year Microsoft invited users to access to the Azure platform for testing purposes in an effort to optimize performance, scalability, and functionality.  At the 2009 Professional Developers Conference in mid-November, Microsoft announced that Azure will go live in January 2010 and begin charging customers on February 1, 2010.   The pending production-ready release of the Azure platform presents a question for Silverlight developers, let alone those working with the ArcGIS Silverlight/WPF API: does Windows Azure provide an effective platform to host Silverlight applications?  To put it simply, yes.  Basically you can use Azure to host, scale, and secure Silverlight Web applications instead of purchasing and maintaining hardware/software solutions in-house.  This same argument applies to other features of the Azure platform ranging from secure off-site data storage, to accessing data in SQL Server, to hosting business logic via Web services.   With this in mind, I'd like to provide a brief walkthrough of how to create and deploy and ArcGIS Silverlight application into the Windows Azure cloud.  

    Note, to complete these steps, you will need to have access to a Windows Azure hosted service.   If you do not have access to a hosted service, you will need to request an invitation token via http://www.microsoft.com/windowsazure/account/ (requires a Live ID account).   When you receive the token, login to http://windows.azure.com/ and claim it to create a hosted service.   Note, as Windows Azure moves closer to production in early 2010, this process may change. 

    Let's get started... 

    1. Install the ArcGIS API for Microsoft Silverlight/WPF

      Assuming you have Visual Studio 2008 (with Silverlight 3 Tools) or 2010, download and install the ArcGIS API for Microsoft Silverlight/WPF

    2. Install Windows Azure Tools for Visual Studio

      Download Windows Azure Tools for the Visual Studio 2008/2010.  The download contains a set of Visual Studio projects and the Windows Azure SDK which includes the Development Fabric to test your Windows Azure application prior to deployment.

    3. Open Visual Studio and create a Windows Azure Cloud Service

      When creating the cloud service, add a single ASP.NET Web Role.  



    4. Add a Silverlight application to the solution

      When adding a Silverlight application in Visual Studio use the ASP.NET Web Application created as a Web Role in the previous step as a host for the Silverlight application.



    5. Add a reference to the core ArcGIS Silverlight assembly in the Silverlight application

      Add a reference in the Silverlight application to the ESRI.ArcGIS.Client.dll.  References will be available in the .NET tab in Visual Studio 2008.  Navigate to the library in Visual Studio 2010.  By default, the ArcGIS Silverlight assemblies are installed into C:\Program Files\ESRI SDKs\Silverlight\v1.1.  If installed on a 64-bit operating system, ArcGIS Silverlight assemblies are installed in the 32-bit (x86) program files directory.

    6. Add a Map, base map layer, and feature layer for SQL Azure spatial data

      First add a namespace reference to ESRI.ArcGIS.Client, then add a Map control to the root container (Grid) in the page (UserControl).  Add a base map layer to provide a geographic context.  Optionally, you can add a dynamic map service or feature layer to overlay on the base layer.  In the following example, the base layer references an ArcGIS Online tiled (cached) map service and the feature layer references a table in a SQL Azure Database accessed via an ESRI MapIt Spatial Data Service deployed in a Windows Azure Web Role.  Map tips have also been configured on the feature layer.   
      <UserControl x:Class="SilverlightApplication1.MainPage"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
          xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
          xmlns:esriConverters="clr-namespace:ESRI.ArcGIS.Client.ValueConverters;assembly=ESRI.ArcGIS.Client">
      
          <UserControl.Resources>
              <esriConverters:DictionaryConverter x:Name="MyDictionaryConverter" />
          </UserControl.Resources>
          
          <Grid x:Name="LayoutRoot" Background="White">
              <esri:Map>
                  <esri:ArcGISTiledMapServiceLayer 
                       Url="http://services.arcgisonline.com/ArcGIS/rest/services/NGS_Topo_US_2D/MapServer"/>
                  <esri:FeatureLayer
                       Url="http://esri.cloudapp.net/databases/Demo/dbo.WorldCities_Geographic" 
                       Color="#99FF0000" >
                      <esri:FeatureLayer.MapTip>
                          <TextBlock 
                               Text="{Binding Converter={StaticResource MyDictionaryConverter}, 
                               ConverterParameter=NAME, Mode=OneWay}" FontSize="14" 
                               Foreground="White" FontWeight="Bold">
                              <TextBlock.Effect>
                                  <DropShadowEffect BlurRadius="10" Color="Black"/>
                              </TextBlock.Effect>
                          </TextBlock>
                      </esri:FeatureLayer.MapTip>                
                  </esri:FeatureLayer>
              </esri:Map>
          </Grid>
      </UserControl>
      
      
    7. Run the cloud service

      Run the cloud service locally using the Azure SDKs Development Fabric.  The Development Fabric provides a Windows Azure simulation environment for you to debug and test an application before deployment. You will need to run Visual Studio in administrator mode to use the Development Fabric.  The ASP.NET Web application configured as a Web Role should host the Silverlight application on a local Web server.  In this example the map control should fill the browser window and display the base and feature layer.



    8. Optional.  Configure the default document for the Web Role

      The ASP.NET Web application configured as a Web Role will host the Silverlight application in an html or aspx page.  If test pages (aspx and html) were created the file name will contain the name of the Silverlight application and the text “TestPage”.  In the Visual Studio IDE you can define the default start page for the Web application in Solution Explorer or in project properties.  However this does not define the default start page for a Windows Azure Web Role.  To define a start page for Windows Azure you can either 1) change the name of the host page (aspx or html) to a standard default document name, such as Default.aspx or 2) add the default document in the web.config (example below).  Note, if you add a default document in the web.config to use as a start page, make sure you clear the default document list to remove any existing document names.  To clear the list use the <clear /> tag illustrated in the example. 

      <system.webServer>
         <defaultDocument>
            <files>
              <clear />
              <add value="Default.htm"/>
            </files>
          </defaultDocument>
      

      If a default document is not available, you must specify the full path to the document hosting the Silverlight application to access it in a browser. 

    9. Publish the cloud service project for Windows Azure

      In Visual Studio, right click on the cloud service solution and select Publish.  This operation will generate a cloud service package (.cspkg) and application settings file (.cscfg) in the build output directory in a folder named “Publish”.


       
    10. Deploy the cloud service project files to Windows Azure

      Login to Windows Azure (http://windows.azure.com/) and create or select a hosted service.  Deploy the cloud service to the Staging or Production site.  Note, deploying, starting, or stopping a service may take longer than 5 minutes to complete.  



      Run the service (if necessary) and the Web Role containing the Silverlight application will initialize and start.  If desired, use the Staging site to test your application.  The Staging site url contains a unique GUID as a subdomain.   You can deploy the Staging application to Production or deploy directly to the Production site if you choose.  The Production site url was defined when the hosted service was created in Windows Azure.    



    11. View the application

      Open a browser and navigate to the Production or Staging site url.  The ArcGIS Silverlight application should load and display.   In this example, the Production site url to the application is:  http://arcgis.cloudapp.net/simple.htm.  To view a styled application with the same data, navigate to the root site http://arcgis.cloudapp.net/.   To enhance the ArcGIS Silverlight application with additional functionality and content use the ArcGIS Silverlight/WPF API Resource Center for further reference: http://resources.esri.com/arcgisserver/apis/silverlight


    For additional information on current and future actions with respect to Windows Azure, see the Windows Azure FAQ.

    Rex Hansen
    ESRI Product Engineer
    ArcGIS Server .NET, Silverlight/WPF, MapIt

     

  • Improve startup time of the map control

    By default, the map control will not render until all layers have initialized.   This process ensures that the map will startup at the full extent of all layers and use the preferred spatial reference discovered at runtime.  However, if you have many layers in your map or if one layer takes a while to initialize, users may have wait a significant amount of time to see the first map.   To improve startup time simply define the initial extent and spatial reference.  Then the map will not need to discover this information at runtime and as a result individual layers will start loading as soon as they initialize.

    You can define the startup extent in your page as follows:

    <esri:Map>
          <esri:Map.Extent>
                <esriGeometry:Envelope XMin="-180" YMin="-90" XMax="180" YMax="90" >
                      <esriGeometry:Envelope.SpatialReference>
                            <esriGeometry:SpatialReference WKID="4326"/>
                      </esriGeometry:Envelope.SpatialReference>
                </esriGeometry:Envelope>
          </esri:Map.Extent>
    ...
    </esri:Map>
    

    If you have multiple tiled layers in your map, make sure their spatial reference matches the one defined for the initial extent or they will not render.   Also see the interactive SDK sample for an example of this in action.
     
    Morten Nielsen
    Senior Software Engineer
    ArcGIS Server.NET, Silverlight/WPF, MapIt

     

  • Use a Bing Maps key in your ArcGIS Silverlight/WPF application

    In November 2009, Bing Maps introduced the ability to generate keys which assign an id to an application that uses Bing Maps services.  A Bing Maps key is similar to a token, but it does not expire and it is associated with a specific application name and URL.  Like a token, the key is included in each request to a Bing Maps service to authorize access. 

    The ArcGIS Silverlight/WPF API uses Bing Maps imagery, geocoding, and routing services via a set of proxy classes in the ESRI.ArcGIS.Client.Bing library - namely the TileLayer, Geocoder, and Routing classes, respectively.  Each class has a Token property which must be set to a valid token generated by a Bing Maps token service for either the production or staging environment.   The Token property can also be set to a Bing Maps key.  Keys can only be used with Bing Maps services in the production environment.   

    To create a Bing Maps key, do the following:

    1. In a browser, navigate to http://www.bingmapsportal.com/.
    2. Create or use a Windows Live ID to log in.
    3. On the "Create and view Bing Maps keys" page enter an application name and URL to create a key.  Currently the name and URL are not validated. 
    4. Copy the key, available on the same page, into your ArcGIS Silverlight or WPF application.  Set the Token property or apply the token in the proxy class constructor.
    5. Run your application.  It will function without requiring you to generate new tokens and update the Token property on a regular basis.  As a result, you can remove any client or server logic to generate and apply Bing Maps tokens.

    This begs the question, why would you use a token instead of a key?

    Since the name or URL associated with a key is not validated, it can be used by multiple applications.  The key itself is present and visible in Web requests from your application to Bing Maps services.  As a result, someone can discover and use your key.  If this is a concern, you can avoid this scenario by using a token which has a maximum expiration time of 8 hours.   Validation of a Bing Maps key will be easier once the Silverlight platform supports the Referer header - which should be available in Silverlight 4 due to be released early next year.   

    Rex Hansen
    ESRI Product Engineer
    ArcGIS Server .NET, Silverlight/WPF, MapIt

  • Using multiple subdomains with a tiled service layer

    Since many Web browsers do not allow more than two requests to a given domain at the same time, some users map multiple subdomains to the same server. This often improves performance for client applications that make many requests to the same server. Currently, ArcGIS Server and the ArcGIS Silverlight/WPF API do not support multiple subdomains for the same service.  However, you can enhance the ArcGIS Silverlight/WPF API to take advantage of a tiled map service hosted on multiple subdomains.  This post will demonstrate how to add support for multiple subdomains to a tiled map service layer to improve map initialization, navigation, and overall performance.  

    The approach involves creating a custom tiled service layer that inherits from ArcGISTiledMapServiceLayer and overriding the GetTileUrl method. In the method simply replace the subdomain part of the URL with any available subdomain hosting the map tiles. You can randomize which subdomain to use, but to ensure that the browser will cache the tiles you'll need to associate a given row/column/level with the same subdomain. To do this use a simple modulus expression that evenly distributes that load on all subdomains and guarantees that a specific row/column/level will always map to the same subdomain.

    The custom tiled service layer looks like this:

    public class ArcGISMultiDomainTileLayer : ArcGISTiledMapServiceLayer
    {
          string[] subDomains = new string[] { 
             "http://subdomain1.",
             "http://subdomain2.",
             "http://subdomain3." 
          };
          
          public override string GetTileUrl(int level, int row, int col)
          {
                string url = base.GetTileUrl(level, row, col);
                string subdomain = subDomains[(level + col + row) % subDomains.Length];
                return url.Replace("http://subdomain1.", subdomain);
          }
    }
    

    Now you can use this layer in your XAML in place of an ArcGISTiledMapServiceLayer:

    <esri:ArcGISMultiDomainTileLayer				
    Url="http://subdomain1.myserver.com/ArcGIS/REST/MyMapService/MapServer/" />


    Morten Nielsen
    Senior Software Engineer
    ArcGIS Server.NET, Silverlight/WPF, MapIt

  • The ArcGIS API for Microsoft Silverlight/WPF version 1.1 is available!

    Version 1.1 of the ArcGIS API for Microsoft Silverlight/WPF is now available for download on the ArcGIS Server Resource Center.   The API includes a set of feature, functionality, and integration enhancments.  One notable difference; you'll download a setup executable which will install and configure Silverlight and WPF assemblies, components, and templates with Expression Blend and Visual Studio.  Here are a few highlights of what's new:

    • Silverlight 3 is now required with version 1.1.  Silverlight 2 is no longer supported. 
    • Silverlight 3 supports element binding, which means you can bind the Map property of a Navigation control to a Map using XAML - no code behind.
    • A complete, interactive design-time experience in Expression Blend 3.  You can drag, drop, and configure ArcGIS Silverlight and WPF controls on the artboard.
    • A set of Silverlight templates are integrated with Expression Blend 3 and Visual Studio 2008.  The templates provide a pre-configured, pre-styled, customizable architecture that enables you to create production worthy mapping applications quickly and easily.
    • Expression Blend 3 introduced behaviors, which are reusable pieces of packaged code that define interactive relationships between controls using XAML.  A new ArcGIS Silverlight and WPF library, ESRI.ArcGIS.Client.Behaviors.dll, includes a set of behaviors and actions to define interactive relationships between user input and Map behavior and content. 

    We invite you to try the new Interactive SDK to see the new features and functionality in action.  In addition, we've created an interactive Symbol Gallery for you to peruse and copy marker, line, and fill symbols for use in your application.  

    Enjoy!

    The ArcGIS Silverlight/WPF Development Team

  • Deep linking to map extents

    With the Silverlight 3 release, we get a new Navigation API that allows you to deep-link into your Silverlight controls, as well as enable the back/forward buttons in the browser. This blog post will show you how you can use the navigation API to link to specific extents in the map, and allow the user to go back and forward in the extent history user the browser history.

    The Navigation API allows you to use parts of the URI in the browser to load specific user controls in your project. To do this, let's first link to a specific user control in our a new default Silverlight + website application. First add a reference to the navigation assembly "System.Windows.Controls.Navigation".

    In our main page control, we create a Frame element, which maps to another "page", in this case Map.xaml. Map.xaml will be the page that holds our map. The MainPage.xaml should look something like this:

    <UserControl x:Class="MapNavigation.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:navigationCtrl="clr-namespace:System.Windows.Controls;
    assembly=System.Windows.Controls.Navigation"
        xmlns:navigation="clr-namespace:System.Windows.Navigation;
    assembly=System.Windows.Controls.Navigation" >
      <Grid>
           <navigationCtrl:Frame>
                  <navigationCtrl:Frame.UriMapper>
                       <navigation:UriMapper>
                            <navigation:UriMapping Uri="" MappedUri="/Map.xaml" /> 
                       </navigation:UriMapper>
                  </navigationCtrl:Frame.UriMapper>
           </navigationCtrl:Frame>
      </Grid>
    </UserControl>


    The Frame uses the UriMapping entry to map the empty (root) URI to the user control "/Map.xaml".  Since the Frame’s Source property is not set, the Map.xaml associated with the empty URI is loaded by a default at runtime.    

    Next, right-click your Silverlight project in Visual Studio, and select to add a new User Control. Name it Map.xaml. This will be the sub-page that will be hosted by MainPage. This must be a of type System.Windows.Controls.Page, so the first step is to change the superclass. Go to Map.xaml's header and change the UserControl tag to navigation:Page and add the navigation prefix. While we are at it we also add the ESRI namespace and a simple map control:

    <navigation:Page x:Class="MapNavigation.Map"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
        xmlns:navigation="clr-namespace:System.Windows.Controls;
    assembly=System.Windows.Controls.Navigation">
           <Grid x:Name="LayoutRoot">
                  <esri:Map x:Name="myMap">
                         <esri:ArcGISTiledMapServiceLayer ID="StreetMap"
           Url="http://server.arcgisonline.com/ArcGIS/rest/services/
    ESRI_StreetMap_World_2D/MapServer" />
                  </esri:Map>
           </Grid>
    </navigation:Page>

    In the code-behind of Map.xaml.cs, change the class declaration to inherit from "Page" instead of "UserControl" :  public partial class Map : Page

    If you run the application now, the application should load up Map.xaml. Notice the browser URI does not contain any parameters and the back button in the browser is disabled.

    So far so good. So now to allow the users to go back and forth when they zoom in/out we first need to tell the navigation service that the state has changed and provide it with a the link to the current extent that changed. We do this by listening to the ExtentChanged event of the map, and in the event handler call NavigationService.Navigate:

    <esri:Map x:Name="myMap" ExtentChanged="myMap_ExtentChanged" >

    private void myMap_ExtentChanged(object sender, ESRI.ArcGIS.Client.ExtentEventArgs e)
    {
           NavigationService.Navigate(new Uri(String.Format(CultureInfo.InvariantCulture,
         "#extent={0},{1},{2},{3}", e.NewExtent.XMin, e.NewExtent.YMin,
    e.NewExtent.XMax, e.NewExtent.YMax), UriKind.Relative));
    }

    The format we use can be anything, but we prefix it with "#" to tell the service that this is a "fragment" within the Map URI. If we didn't do this, the service would try and load a new instance of Map.xaml causing the map to reset. If we run the application now, everytime you change the extent, the browser URI will update:

    Notice the "$" symbol which signifies a fragment that contains extent parameters.  The fragment is handled by the Map page which is mapped to the default or root URI. 

    The back and forward buttons now work, but nothing happens when we click them. We still need to handle when the fragment changes and set the map extent according. We do this by overriding Page.OnFragmentNavigation. This method is called every time the browser fragment after "#$" has changed. In this method we will parse out the extent and set the extent of the map. Notice that we check if the extent really has changed. This is because the code in myMap_ExtentChanged also causes this method to get called, but in those cases there is no need to update the extent, since it already happened. Doing that could cause an infinite loop. Similar we ignore the code in the extent changed handler if we update the extent in OnFragmentNavigation using a simple boolean flag:

    protected override void OnFragmentNavigation(FragmentNavigationEventArgs e)
    {
           if(e.Fragment.StartsWith("extent="))
           {
                  try
                  {
                         string[] vals = e.Fragment.Substring(7).Split(new char[] { ',' });
                         double xmin = Double.Parse(vals[0]);
                         double ymin = Double.Parse(vals[1]);
                         double xmax = Double.Parse(vals[2]);
                         double ymax = Double.Parse(vals[3]);

                         Envelope mapExtent = myMap.Extent;
                         Envelope newExtent = new Envelope(xmin, ymin, xmax, ymax);

                         if (mapExtent==null || !AreEqual(mapExtent, newExtent, 0.000000001))
                         {
                               flag = true;
                               myMap.Extent = newExtent;
                         }
                  }
                  catch { }
           }
           base.OnFragmentNavigation(e);
    }

    bool flag = true;
    private void myMap_ExtentChanged(object sender, ESRI.ArcGIS.Client.ExtentEventArgs e)
    {
           if (flag) flag = false;
           else
                NavigationService.Navigate(new Uri(String.Format(CultureInfo.InvariantCulture,
         "#extent={0},{1},{2},{3}", e.NewExtent.XMin, e.NewExtent.YMin,
    e.NewExtent.XMax, e.NewExtent.YMax), UriKind.Relative));
    }


    Now when you run the application, you can use the back and forward buttons to visit previous extents, you can copy/paste the URL into a different browser or email it, and the map will start up at the same location.

    Download a sample from our development server - view the sample live to see it in action.

    You can learn more about the navigation framework on the following links:
    Silverlight Navigation framework screencast
    Tim Heuer's blog on the Navigation framework
    Tim Heuer's blog on Navigation behavior 
     

    Morten Nielsen
    Senior Software Engineer
    ArcGIS Server.NET, Silverlight/WPF, MapIt

  • Using services across schemes

    A number of questions have surfaced recently regarding support for ArcGIS Server services over a scheme different than a host application that uses the ArcGIS API for Microsoft Silverlight.  For example, when hosting an ArcGIS Silverlight API application on https that accesses ArcGIS Server services over http, the service fails to display as a layer in the map.  In this post I'll discuss a set of common issues encountered with cross scheme restrictions that explain this behavior - and present a few expectations for what should work.  Before we dive into this topic though, let's cover some background.  For security reasons, the Silverlight runtime restricts access to data and services for specific classes across schemes, domains and zones.   These restrictions may impact your use of data and services in the ArcGIS Silverlight API.  Scheme defines the protocol by which you access a resource.   This includes http, https, file, ftp, etc.   From the Silverlight perspective, scheme applies to the host application and resources it will use.  Usually Silverlight applications are hosted in a Web page, thus the host scheme is http or https.   Likewise, resources such as services and images are usually exposed over http or https.  

    The ArcGIS Silverlight API requires that applications be hosted on a Web server, thus the host scheme will be either http or https.  Resources used by components of the ArcGIS Silverlight API are often consumed as services or images on a Web server, so they share the same scheme requirements (http or https).  The use of services and images in the ArcGIS Silverlight API is impacted by cross-scheme restrictions in two ways:  1) when using services to retrieve metadata about a layer to display in a map or query and 2) when displaying map service layers in a map requires retrieving a dynamic map image or a set of map image tiles.  In short, when working across different schemes #1 is possible, #2 is not.       

    Since cross-scheme access to a service is allowed, how do you enable it?
     
    The solution is specific to the Silverlight platform.  You need to create a client access policy file on the services Web server that enables full access.  For example, the client access policy file on ArcGIS Online allows full access to http and https services on ArcGIS Online from Silverlight applications hosted on http or https. You can view the file in a browser via the url:  http://services.arcgisonline.com/clientaccesspolicy.xml



    The file contains two lines that affect scheme support.  The following line in the client access policy file allows access from http hosted apps to http services -and- allows access from https hosted apps to http and https services:

    domain uri="*"
    It does not allow access from http hosted apps to https services. This is handled by the next line:
    domain uri="http://*" 

    Both entries work together to allow full access.

    Note, the Silverlight 3 runtime will recognize a domain uri equal to "https://*".   This is only necessary if you want to restrict access to Silverlight applications hosted on https.  See the Network Security Access Restrictions in Silverlight topic on MSDN for more information.

    Even with cross-scheme access to services enabled, you cannot load an image across schemes in a Silverlight application.  It is a limitation imposed by the Silverlight platform.  Take a look at the document URL Access Restrictions in Silverlight on MSDN for more details.  Note the cross-scheme entry for the Image class is "Not Allowed".  This restriction is often to blame when a layer, accessed across schemes, fails to display in the ArcGIS Silverlight API Map control.   

    So, with this in mind, if the client access policy file allows complete access to site resources (as the ArcGIS Online and serverapps.esri.com do), what should you expect to work in the ArcGIS Silverlight API?  

    Silverlight Hosted
    Scheme

    Service
    Scheme

    Service
    access

    Image
    access

    HTTP

    HTTP

    Yes

    Yes

    HTTP

    HTTPS

    Yes

    No

    HTTPS

    HTTP

    Yes

    No

    HTTPS

    HTTPS

    Yes

    Yes

    The problematic combinations are clear - cross scheme access to map images (dynamic or tile) are not accessible. So how can you resolve this?  For ArcGIS Server services the solution involves changes on the server.   

    For dynamic (non-cached) map services the ArcGIS Silverlight API sends a request to export a map image to the Url defined on an ArcGISDynamicMapServiceLayer. The response format is JSON, which includes a url to the output image. The output virtual directory, which includes the scheme, is defined by the service. Unfortunately you cannot have multiple output virtual directories or define the scheme for the output image url.

    So how can you solve this on the server? Create two services from the same map config file (mxd, msd): one that generates output in a virtual directory accessible via https and another for http. For example, two services are available on http://serverapps.esri.com: California - which outputs to an http directory; California_SSLOUT - which outputs to an https directory.  The following table highlights the results of different scheme combinations for the host and service:

    Silverlight Hosted Scheme

    Scheme and Service access

    Result

    HTTP

    HTTP - California

    Works

    HTTP

    HTTP - California_SSLOUT

    Does not work (cross scheme image request)

    HTTP

    HTTPS - California

    Works

    HTTP

    HTTPS - California_SSLOUT

    Does not work (cross scheme image request)

    HTTPS

    HTTP - California

    Does not work (cross scheme image request)

    HTTPS

    HTTP - California_SSLOUT

    Works (prompt to display mixed content - http service request)

    HTTPS

    HTTPS - California

    Does not work (cross scheme image request)

    HTTPS

    HTTPS - California_SSLOUT

    Works

    For tiled (cached) map services, the ArcGIS Silverlight API constructs requests for tiles. The scheme in the tile requests is defined by the scheme in the Url for the ArcGISTiledMapServiceLayer.  In this case the service cannot be modified to return a url with a specific scheme, thus the REST endpoint must be available via a scheme that matches the host application.  This limitation is frequently encountered when working with "free" ArcGIS Online tiled map services.   If you need to host your ArcGIS Silverlight API application over https, thus far you've been unable to access ArcGIS Online free services directly because they were not available over https.  This will change - very soon ArcGIS Online will provide access to "free" services over https.

    Rex Hansen
    ESRI Product Engineer
    ArcGIS Server .NET, Silverlight/WPF, MapIt

  • Troubleshooting blank layers

    The Silverlight API is a client application dependent on services that might fail or be unavailable. In general, the Map control will not throw an exception if one service fails. This means that if one service is down, the application will continue to run and access the remaining layers. However, it also means that you don’t automatically get any error reporting, and if all your services fail, you will just end up with a blank map.

    When looking at the ESRI Silverlight forums, several users have reported issues with getting their layers to display or encountering blank maps. This blog post tries to outline the common reasons why a service does not display in the map, and how to remedy it.

    Most of the problems with a missing layer are related to browser security issues, so to trouble shoot client applications, there is one tool that I will recommend anyone to get familiar with: Fiddler. This is a free HTTP tracing tool that tracks the requests and responses between the browser and the web server, and logs if any requests failed. You can download this tool from http://www.fiddler2.com/.

    Once installed and launched, any network traffic initiated by Internet Explorer will be tracked by Fiddler. Note that any traffic to http://localhost/ is not tracked by default, and requires extra configuration. Other browsers might also require explicit configuration to work with Fiddler. I will be using Fiddler several times in this blogpost to track down issues you may experience.

    Cross-domain limitations

    Let’s for sake of argument say you installed ArcGIS Server on your own server, and you are trying to use one of its services. You first navigate to a service at your REST endpoint and copy/paste the URL to a layer in your Silverlight application, but the layer never shows. Let’s see what happens in Fiddler:

    We see two requests. Both are highlighted in red, meaning an error occurred, and from the result code "404" we can see that none of these files were found. So what are these files it tries to get from the root of my map server?

    Silverlight does not allow you to make requests to servers hosted on a different host than your web application. In this case I was running my application on http://localhost/, and trying to access a service on http://myserver/.  Silverlight will first verify that the server allows other applications to perform requests against that server. It does this by trying to download a clientaccesspolicy.xml file from the domain. This is a Silverlight access configuration file telling the client who can call the server and which parts it can request. Flex has a similar pattern in place using a crossdomain.xml file. If it fails to find the clientaccesspolicy.xml file, Silverlight will try and search for Flex’s crossdomain.xml file and use that instead. If both fail, services on the server will be unavailable, the layer will not be able to initialize itself, and it will not render in the map. You can read more about this Silverlight security feature here, and you can look at the policy file that ArcGIS Online uses here.  If your services and application are hosted on the same domain AND port number, this should not be an issue. It’s worth noting the port constraint, since Visual Studio by default will run the autogenerated test-website on a different port on localhost than your ArcGIS REST services (not to mention that you shouldn’t be using localhost in the Url for layer since ‘localhost’ would mean something different to each client hitting your Silverlight application).

    The cross domain restriction is by far the number one reason for a service failing to load.

    Cross-scheme access

    Another security feature in Silverlight is one preventing you from requesting data across different schemes, like http:// https:// and file://.  If you try to run a Silverlight application with a Map control using file:// in your browser URL, you might see this in your Map control:

     

    This is because the Map control will need to be in an application hosted on a http or https website, but you are running the application from the file system (scheme).  To resolve this, make sure your Silverlight application hosted by a Web server and make sure the Web site is set as the startup project in Visual Studio. When you start a new Silverlight application project in Visual Studio, make sure you say yes to create a Web site to host your application in:



    Restrictions also apply to http and https schemes. If your application is hosted on https and your service is hosted on http, or visa versa, you can access the service if explicitly permitted by the clientaccesspolicy.xml.  You cannot access images across schemes though, so while a request for service metadata may succeed, the request for a dynamic map image or cache tile will fail.   An upcoming blog post will cover this scenario in more detail. 

    Hopefully at this point you’re able to see your map, and Fiddler will show something like:

    In sequence you will see one successful request for clientaccesspolicy.xml, then a request for the service metadata, next a request for an image url, and lastly for the actual map image that was generated. Depending on which service type you are using, the last two requests may be different. The above example is using a dynamic map service.

    Service output folder configuration

    If you still have problems displaying the map service and you see something like below in Fiddler, you might have a configuration issue on your server end:

    Notice how it requests images from "myserver", but in the end tries to request an image from "localhost" (or some other domain/website unknown to the Silverlight client). If this is the case, the output folder of your ArcGIS Server service is not set up correctly.  Use Manager or Catalog to define the appropriate url to the output folder

    Unsupported file format (GIF)

    Silverlight does not support the GIF image format. If you are using a tiled service that has the tiles cached as GIF, it will not work with the ArcGIS Silverlight API.

    Tiled layers - Wrong spatial reference

    ArcGISTiledMapServiceLayer does not support re-projecting on the fly. This means that if you try and mix cached layers of different spatial reference, one or more services will not display. The first layer in the ESRI Map Control that has a spatial reference set will define the spatial reference for the entire map*, and any cached layer not matching this spatial reference will not load. You will see a request for the service metadata in Fiddler, but no requests for any image tiles. 

    *Note that you can override the default map projection by explicitly setting a startup extent with a spatial reference set. See the sample in the Interactive SDK. 

    Handling service errors

    In the beginning I mentioned that some servers might be unavailable, and the Map control will continue to run with the remaining layers. If this is the case, you may want to let the user know that there was a problem loading a layer.  All layers have an "InitializationFailed" event you can subscribe to, that will fire in the event of a layer failing to initialize. You can also use this yourself to track down any initialization issues as well.
    To listen for it, add the highlighted code to your layer definition:

    <esri:ArcGISDynamicMapServiceLayer
     ID="StreetMap"
     InitializationFailed="layer_InitializationFailed"
     Url="http://myserver/ArcGIS/rest/services/StreetMapUSA/MapServer" />

    In the event handler you can check the InitializationFailure exception to determine what the problem was, and display a message to the user. Example:

    private void layer_InitializationFailed(object sender, EventArgs e)
    {
      Layer layer = sender as Layer;
      MessageBox.Show(string.Format("Layer '{0}' is currently unavailable. Error: {1}",
         layer.ID, layer.InitializationFailure.Message));
    }

    Morten Nielsen
    Senior Software Engineer
    ArcGIS Server.NET, Silverlight/WPF, MapIt

  • Using Behaviors to enable MouseWheel in Full Screen and Out-of-browser

    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

  • Welcome to the Silverlight/WPF Blog!

    I would like to take some time and welcome you to the Silverlight blog and cover some initial thoughts.  First a quick status of where things are...  

    Overall, the Silverlight/WPF API has been received extremely well within the community.  So far, we have logged over 2000 downloads since we went final (UC 2009) and it does not show any signs of slowing down.  The forums are very active with the community using the Silverlight API and the Silverlight team members answering a lot of the forum postings directly. The  Code Gallery is very active as well, which is where we are posting some additional work that the team thought would interest you, like the Silverlight Showcase app, KML, WMS, GeoRSS and Heat Map layers not to mention a host of user samples also posted on the code gallery.  One notable achievement by the team is the ESRI ArcGIS Silverlight Toolkit CodePlex site.  This is a first for any development team at ESRI and we hope to keep the trend moving forward.  

    We were also able to build a small, light weight product on top of the V1.0 Silverlight/WPF API called ESRI MapIt.  This is a cool product, light weight, easy to use and install, very fast and of course, support for both x86 and x64. Keep an eye on the MapIt blog for more info. 

    As a team, we are small, agile, and very passionate about our work with Silverlight and WPF and hope to keep you happy along the way. 

    The obvious question is: What’s next?

    Well, the team is actively working on a v1.1, which we will make available soon.  It will include a number of bug fixes, Design time support for both Visual Studio and Expression 3, and a move up to Silverlight 3.  Yes, we are moving up to Silverlight 3; and based on the latest ArcGIS Developer Poll, most of you are too.  Of course, there are a few more things happening with v1.1, but that is for another post.  

    Back to Silverlight 3 for a moment, there so many benefits to working with SL3 that Microsoft made it very difficult for us not to make the move.  Things like element binding, enhanced graphics, the new Bitmap API and offline application support.  Tim Heuer has a good blog entitled "A guide to Silverlight 3 new features".  In this post Tim helps you understand some of the new features and benefits of SL3.    

    The WPF API is also going strong.  I continue to hear how people are using the WPF API in some real cool apps.  Apps like Surface Apps developed by the Application Prototype lab and WPF API based apps that use ArcGIS Engine for advanced disconnected scenarios and analysis.  One notable piece of feedback that we received from the community was to also have a WPF specific SDK.  Well, we heard you and in the next couple of weeks, we will make this available for download from the Resource Center.  

    With all that said, we would also like to ask you, the ESRI Silverlight community, to help us along the way and provide the feedback we need to help you get your job(s) done.  As we have said time and time again at conferences and such, we are adhering to a concept of "less is more".  This means that the core API will stay as small and tight as possible only adding features that the users are asking for.  Use the forums, send us emails, talk with your regional reps; however you want to do it, but get us the information we need to help you.

    E
    njoy the API’s!  We look forward to seeing all the cool things you are and will be building with them.

    Art Haddad
    ESRI Development Lead and Architect
    ArcGIS Server .NET, Silverlight/WPF, MapIt