I am developing a Windows Form that will take user's latitude and longitude, perform some long calculations and display user's location and some routes on the map. The map will be shown in a separate WPF window using Bing Maps API. Since the calculations that need to be performed after user enters latitude and longitude are complicated and take a lot of time, I need to perform those calculations in a background thread and call new WPF window from this background thread.
At first, I wasn't able to open WPF window from a background thread because of thread affinity, but I fixed it after setting apartment state of the thread to ApartmentState.STA
. Here is the procedure that gets called after user enters latitude and longitude and presses on a button on Winform:
private void button1_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(foo);
t1.SetApartmentState(ApartmentState.STA);
t1.IsBackground = true;
t1.Start();
}
The procedure that gets executed when thread starts is foo()
. I have read on the forums that I need to call System.Windows.Threading.Dispatcher.Run()
so that WPF window doesn't close as soon as thread finishes:
private void foo()
{
MainWindow window = new MainWindow(lat.Text, lon.Text);
window.Show();
window.Closed += (sender2, e2) => window.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
}
WPF window is called MainWindow. Here is its code:
public partial class MainWindow : Window
{
public MainWindow(double latitude, double longitude)
{
InitializeComponent();
myMap123.Focus();
//Set the map mode to Aerial with labels
myMap123.Mode = new AerialMode(true);
}
}
Finally, in case some of you need xaml file for WPF window, here it is:
<Window x:Class="WPFTestApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF"
Title="MainWindow" Height="350" Width="525">
<Grid>
<m:Map CredentialsProvider="KEY" x:Name="myMap123"/>
</Grid>
</Window>
When I input some latitude and longitude and press on the button, WPF window does appear, but the Bing Map doesn't show world map. Instead, background is grey, and if I try to zoom, or change the size of window, System.NullReferenceException
(Object reference not set to an instance of an object) gets thrown. Debugger tells me that exception is thrown at line System.Windows.Threading.Dispatcher.Run();
. However, if I do not try to center the map and don't set map to Aerial mode, everything works fine. What should I do so that I can call WPF window from background thread and change Bing Map's properties at runtime without any problems?
I already checked that everything would have worked fine if WPF window was getting called from the main UI thread.
Interestingly, if I close WPF window and press on the button again, new WPF window shows Bing Maps normally and System.NullReferenceException
doesn't get thrown.