Using SpatialAce in WPF applications
It’s been a long while since I blogged about SpatialAce. It’s even got a new name since the last time i wrote about it: Carmenta Engine. So I thought I’d write one last post about this excellent GIS map engine; this time about using it in a Windows Presentation Foundation (WPF) application.
Since Carmenta Engine is an ActiveX control, you need to use a WindowsFormsHost wrapper class. I will show a technique where we will create an intermediate WPF wrapper that will enable us to implement a few custom dependency properties that we can use for setting configurations files and view names in XAML.
Start by adding a new WPF Library project to your solution. Name the new project CarmentaEngine. Then add a new Windows Forms UserControl and name it CarmentaEngineFormsControl. Make sure that you choose a Windows Forms control, not the WPF equivalent. In this UserControl, you drop your Carmenta Engine ActiveX control and set it’s dock property to fill.
Now create a WPF UserControl in the same project and drop a WindowsFormsHost into it. Name the WPF UserControl CarmentaEngineControl. We can now add the just created Windows Forms UserControl to the WPF UserControl. Sounds a little complicated? Well, the benefit here is that we can implement dependency properties for Carmenta Engine in the WPF UserControl that we can use from XAML later.
The file CarmentaEngineControl.xaml should look something like this:
<UserControl x:Class="CarmentaEngine.CarmentaEngineControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
xmlns:code="clr-namespace:CarmentaEngine"
Height="300" Width="300" >
<Grid>
<my:WindowsFormsHost Name="windowsFormsHost1">
<code:CarmentaEngineFormsControl x:Name="carmentaEngineFormsControl"/>
</my:WindowsFormsHost>
</Grid>
</UserControl>
We’d like to expose the ConfigurationFile and ViewName property of the Carmenta Engine ActiveX control as dependency properties. This is very straightforward code, the only thing to look out for is that we should not set the property values until we have both of them. Setting ViewName without a ConfigurationFile value does not make sense. Here’s the code behind from CarmentaEngineControl.xaml.cs:
public partial class CarmentaEngineControl : UserControl {
public static readonly DependencyProperty ConfigurationFileProperty;
public static readonly DependencyProperty ViewNameProperty;
private string viewName = null;
private string path = null;
public CarmentaEngineControl() {
InitializeComponent();
}
static CarmentaEngineControl() {
ConfigurationFileProperty = DependencyProperty.Register
("ConfigurationFile", typeof (string), typeof (CarmentaEngineControl),
new FrameworkPropertyMetadata
(null, FrameworkPropertyMetadataOptions.None, OnConfigurationFileChanged));
ViewNameProperty = DependencyProperty.Register
("ViewName", typeof(string), typeof(CarmentaEngineControl),
new FrameworkPropertyMetadata
(null, FrameworkPropertyMetadataOptions.None, OnViewNameChanged));
}
private static void OnViewNameChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e) {
CarmentaEngineControl control = d as CarmentaEngineControl;
if (control != null) {
control.viewName = (string) e.NewValue;
control.InitializeEngine();
}
}
private static void OnConfigurationFileChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e) {
CarmentaEngineControl control = d as CarmentaEngineControl;
if (control != null) {
control.path = (string) e.NewValue;
control.InitializeEngine();
}
}
public string ConfigurationFile {
get { return (string) GetValue(ConfigurationFileProperty); }
set { SetValue(ConfigurationFileProperty, value); }
}
public string ViewName {
get { return (string)GetValue(ViewNameProperty); }
set { SetValue(ViewNameProperty, value); }
}
private void InitializeEngine() {
if (path != null && viewName != null) {
FileInfo fileInfo = new FileInfo(path);
if (fileInfo.Exists) {
AxSpaceX spaceX = carmentaEngineFormsControl.axSpaceX1;
spaceX.ConfigurationFile = path;
spaceX.NameSpace = Path.GetFileNameWithoutExtension(path);
spaceX.ViewName = viewName;
spaceX.Tool = new RoamToolClass();
}
}
}
}
That’s basically all there is to it. Now, in your original WPF application project, reference the WPF Library project from above and add the following code to your XAML:
<CarmentaEngine:CarmentaEngineControl
Margin="31,0,475.75,19" Height="177" VerticalAlignment="Bottom"
ConfigurationFile="path to configuration file"
ViewName="the name of your view"/>
Don’t forget to reference the CarmentaEngine project in your header:
xmlns:CarmentaEngine="clr-namespace:CarmentaEngine;assembly=CarmentaEngine"
Since last week, I no longer work at Carmenta so I can’t verify the syntax. I based the code on some notes on how I did this a few weeks ago and I hope I got all the details right. I should also say that this was my first encounter with WPF and I found the MSDN documentation to be a little terse. In other words: there might be syntax errors above and better ways to do this, but I found the technique to have a separate WPF library with custom dependency properties to be pretty powerful.
April 29th, 2008 at 16:31
Cool stuff!
May 1st, 2008 at 13:01
Glad you liked it, Reine. I realized as I just read it though that I’ve failed to mention why setting properties using DependecyProperty in XAML is worth bothering about. The reason is of course data binding. Maybe I should do a second post about that? I could make it a two-parter…
July 5th, 2008 at 13:28
Hello from Spain !
I work with Carmenta Engine/Spatial ace and it is great to know about a blog that write carmenta’s stuff.
Is there more blogs or communities about this?
July 5th, 2008 at 20:10
Fernando, I don’t know about other blogs or communities but I’m glad you liked the post. Please let me know if there is anything in particular you’d like covered and perhaps I can write something up.
December 10th, 2008 at 10:25
Tack – du räddade precis min dag
December 10th, 2008 at 22:46
Roligt att du hade nytta av koden, Tomas.
February 11th, 2010 at 10:17
I want to know , where can we get the SpaceAce4 Activex Control present in the SpatialAceApplicationDemo .
thanks.
February 11th, 2010 at 10:18
I want to know , where can we get the SpaceAce4 Activex Control present in the SpatialAceApplicationDemo .
thanks.
February 11th, 2010 at 21:37
Abhra, you can get the ActiveX Control from the Carmenta web site:
http://www.carmenta.com/