How to host an ArcGIS Engine MapControl in a WPF application


Summary
Microsoft's Windows Presentation Foundation (WPF) provides the facility to host Windows Forms controls, allowing developers to continue using their existing Windows Forms controls within a WPF application. A combination of code and Extensible Application Markup Language (XAML) is used in this topic to host an ArcGIS Engine MapControl inside a WPF window.


Using the WindowsFormHost control

Windows Forms controls can be placed on a WPF window or page by using the WindowsFormsHost control, which provides a container where a single Windows Forms control can be hosted.

Creating the WPF application

Do the following steps to create the WPF application:
  1. Start Visual Studio.
  2. Create a WPF application project and name it MapHostedInWPF.

Adding project references

Add the following references to the MapHostedInWPF project:
  • ESRI.ArcGIS.AxControls—Contains the AxMapControl.
  • ESRI.ArcGIS.System—Contains the AoInitialiseClass class (used to set up the ArcGIS Engine license).
  • ESRI.ArcGIS.Version—Contains runtime manager functionality to bind a specific ArcGIS installation on the machine.

Dragging and dropping WindowsFormsHost

From the toolbox in the Controls section, drag-and-drop a WindowsFormsHost control onto the window.
When coding WPF, there is often more than one way to achieve the same end result, as every feature of XAML has an alternative implementation in the code, and the Visual Studio designer allows you to author XAML directly, or use more "traditional" drag-and-drop methods to build the user interface (UI). In this case, you can alternatively add a WindowsFormsHost control in the markup.

Modifying XAML attributes

Do the following steps to modify XAML attributes:
  1. Double-click MainWindow.xaml in the Solution Explorer to open the designer.
  2. In the XAML editing pane, modify the XAML attributes on the WPF elements as shown in the following code example.
    1. Change the Windows Title attribute to, MapControl hosted in WPF.
    2. Change the Name attribute of WindowsFormsHost element to, mapHost.
    3. Add a Windows loaded event with the default name, Window_Loaded.

Adding Windows loaded event

Do the following steps when you add a Windows loaded event:
  1. Type Loaded= in the markup code. A context menu showing <New Event Handler> appears.
  2. Press the Tab key to automatically insert the Window_Loaded text string, which provides a Window_Loaded stub in the code behind file. See the following screen shot:
WPF elements have IntelliSense support in XAML. If the Tab key is not pressed, the Window_Loaded stub code is not automatically provided. Make sure the name of the loaded event in the markup code, matches the exact name of the event handler in the code behind the file.
See the following code example:
[C# XAML]
<Window
  x:Class="MapHostedInWPF.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="MapControl hosted in WPF"
  Loaded="Window_Loaded"
  Height="331"
  Width="378"
  xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration">
  <Grid>
    <my:WindowsFormsHost Margin="19,19,17,28" Name="mapHost"/>
  </Grid>
</Window>
[VB.NET XAML]
<Window
  x:Class="MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="MapControl hosted in WPF"
  Height="331"
  Width="378"
  Loaded="Window_Loaded"
  xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration">
  <Grid>
    <my:WindowsFormsHost Margin="19,19,17,28" Name="mapHost"/>
  </Grid>
</Window>

Initializing ArcGIS Engine licenses

Do the following steps to programmatically initialize ArcGIS Engine licenses in a WPF environment:
  1. Click to expand the App.xaml (C#) or Application.xaml (VB .NET) node in the Solution Explorer.
  2. Double-click App.xaml.cs or Application.xaml.vb to open the code file for the application.
  3. Replace the file's content with the following code example to initialize ArcGIS Engine when the application starts:
[C#]
using System.Windows;
using ESRI.ArcGIS.esriSystem;

namespace MapHostedInWPF
{
    public partial class App: Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            InitializeEngineLicense();
        }

        private void InitializeEngineLicense()
        {
            AoInitialize aoi = new AoInitializeClass();

            //More license choices can be included here.
            esriLicenseProductCode productCode =
                esriLicenseProductCode.esriLicenseProductCodeEngine;
            if (aoi.IsProductCodeAvailable(productCode) ==
                esriLicenseStatus.esriLicenseAvailable)
            {
                aoi.Initialize(productCode);
            }
        }
    }
}
[VB.NET]
Imports ESRI.ArcGIS.esriSystem

Class Application
    
    Protected Overrides Sub OnStartup(ByVal e As System.Windows.StartupEventArgs)
    MyBase.OnStartup(e)
    InitializeEngineLicense()
End Sub

Private Sub InitializeEngineLicense()
    Dim aoi As AoInitialize = New AoInitializeClass()
    
    'More license choices can be included here.
    Dim productCode As esriLicenseProductCode = esriLicenseProductCode.esriLicenseProductCodeEngine
    If aoi.IsProductCodeAvailable(productCode) = esriLicenseStatus.esriLicenseAvailable Then
        aoi.Initialize(productCode)
    End If
End Sub

End Class
Do not use an ArcGIS Engine license control in a WPF environment. Initialize the ArcGIS Engine license when the application starts, instead of when Windows starts.

Binding to a specific ArcGIS product

Starting from ArcGIS 10, it is required to bind to a specific ArcGIS installation on your machine. Perform this step before the logic of ArcGIS license initialization. Add the following code example before the InitializeEngineLicense method is called:
[C#]
ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Engine);
[VB.NET]
ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Engine)

Creating the AxMapControl

Do the following steps to create the AxMapControl:
  1. Click to expand the MainWindow.xaml node in the Solution Explorer.
  2. Double-click MainWindow.xaml.cs or MainWindow.xaml.vb to open the code file for the window.
  3. Replace the file's content with the following code example. AxMapControl is created programmatically and set to the Child property of the mapHost element at the Windows constructor.
To host a Windows Forms control in a WPF element, assign the Windows Forms control to the Child property. A single WindowsFormsHost control can only have one child. For more information, see the Microsoft Developer Network (MSDN) Web site topic, WindowsFormsHost.Child Property.
[C#]
using System.Windows;
using System.Windows.Forms;
using System.Drawing;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Controls;

namespace MapHostedInWPF
{
    public partial class MainWindow: Window
    {
        AxMapControl mapControl;

        public MainWindow()
        {
            InitializeComponent();
            CreateMapControl();
        }
        // Create an AxMapControl and host it in the WindowsFormsHost element.
        private void CreateMapControl()
        {
            mapControl = new AxMapControl();
            mapHost.Child = mapControl;
        }
    }
}
[VB.NET]
Imports System.Windows
Imports System.Windows.Forms
Imports System.Drawing
Imports ESRI.ArcGIS.Controls
Imports ESRI.ArcGIS.esriSystem

Class MainWindow
    Private mapControl As AxMapControl

    Public Sub New()
        InitializeComponent()
        CreateMapControl()
    End Sub
    
    Private Sub CreateMapControl()
        mapControl = New AxMapControl()
        mapHost.Child = mapControl
    End Sub
    
End Class

Setting AxMapControl properties

Unlike the Windows forms environment, it is not possible to access ArcGIS Engine control properties in the WPF designer. As a result, MapControl properties need to be set programmatically. In the MainWindow.xaml.cs or MainWindow.xaml.vb file, add the following code example after the CreateMapControl method to set the dock and background color of the MapControl:
[C#]
private void SetMapProperties()
{
    //Set the properties of AxMapControl.
    mapControl.Dock = DockStyle.None;
    mapControl.BackColor = Color.FromArgb(233, 233, 233);
}
[VB.NET]
Private Sub SetMapProperties()
    'Set the properties of AxMapControl.
    mapControl.Dock = DockStyle.None
    mapControl.BackColor = Color.FromArgb(233, 233, 233)
End Sub
You can set the AxMapControl's properties when the window loads. Set the AxMapControl properties after the Child property of the specified WindowsFormsHost; otherwise, unexpected behaviors occurs. The Dock property of the MapControl hosted in WPF behaves differently from the Windows Forms (experiment with it to meet the needs of your application).

Wiring up the events of AxMapControl

ArcGIS Engine control events are not accessible in the WPF designer (they need to be wired up programmatically). In the MainWindow.xaml.cs or MainWindow.xaml.vb file, add the following code example after the SetMapProperties method to wire up the MapControl's OnMouseMove event:
[C#]
private void WireMapEvents()
{
    mapControl.OnMouseMove += new IMapControlEvents2_Ax_OnMouseMoveEventHandler
        (mapControl_OnMouseMove);
}

private void mapControl_OnMouseMove(object sender,
    IMapControlEvents2_OnMouseMoveEvent e)
{
    System.Console.WriteLine(e.mapX.ToString());
}
[VB.NET]
Private Sub WireMapEvents()
    AddHandler mapControl.OnMouseMove, AddressOf mapControl_OnMouseMove
End Sub

Private Sub mapControl_OnMouseMove(ByVal sender As Object, ByVal e As IMapControlEvents2_OnMouseMoveEvent)
    System.Console.WriteLine(e.mapX.ToString())
End Sub

Loading the map

The last step is to set up the map properties and events, and load a .mxd file into the map when the window finishes loading. In the MainWindow.xaml.cs or MainWindow.xaml.vb file, add the following code example after the WireMapEvents method:
[C#]
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    SetMapProperties();
    WireMapEvents();

    // Specify your .mxd file here.
    mapControl.LoadMxFile(
        "C:\\Program Files (x86)\\ArcGIS\\DeveloperKit10.1\\Samples\\data\\GulfOfStLawrence\\Gulf_of_St._Lawrence.mxd");
}
[VB.NET]
Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    SetMapProperties()
    WireMapEvents()
    
    ' Specify your .mxd file here.
    mapControl.LoadMxFile("C:\Program Files (x86)\ArcGIS\DeveloperKit10.1\Samples\data\GulfOfStLawrence\Gulf_of_St._Lawrence.mxd")
End Sub

Running the project

Do the following steps to run the project:
  1. Press F5 to run the application and load the specified map.
  2. Move the mouse pointer around the map to verify how the OnMouseMove event responds.
  3. The developed sample application should look like the following screen shot.


See Also:

Sample: MapViewer hosted in a WPF
WindowsClient.NET
Walkthrough: Hosting a Windows Forms Composite Control in Windows Presentation Foundation
Using ArcGIS Engine controls in WPF
How to add a Windows Form containing a MapControl to a WPF application




Additional Requirements
  • .NET Framework 3.5 as the target framework.

Development licensing Deployment licensing
Engine Developer Kit ArcGIS for Desktop Basic
ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced
Engine