2014-10-28 43 views
0

我正在开发一个Windows窗体,它将采用用户的经纬度,执行一些长时间的计算并在地图上显示用户的位置和一些路线。该地图将使用Bing地图API在单独的WPF窗口中显示。由于在用户输入经纬度后需要执行的计算很复杂,需要花费很多时间,因此我需要在后台线程中执行这些计算并从后台线程调用新的WPF窗口。正在从Winform调用Bing Map的WPF窗口

起初,由于线程关联性,我无法从后台线程打开WPF窗口,但是在将线程的公寓状态设置为ApartmentState.STA之后,我对其进行了修复。这里是用户输入经纬度和后压上的按钮在WinForm的被调用的程序:

private void button1_Click(object sender, EventArgs e) 
{ 
    Thread t1 = new Thread(foo); 
    t1.SetApartmentState(ApartmentState.STA); 
    t1.IsBackground = true; 
    t1.Start(); 
} 

线程启动时被执行的过程foo()。我已阅读,我需要调用System.Windows.Threading.Dispatcher.Run()论坛,使WPF窗口不会立即关闭的线程完成:

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窗口称为主窗口。下面是它的代码:

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); 
    } 
} 

最后,如果一些你需要的WPF窗口的XAML文件,那就是:

<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> 

当我输入一些纬度和经度,然后按一下按钮, WPF窗口确实出现,但Bing Map不显示世界地图。相反,背景是灰色的,如果我尝试缩放或更改窗口的大小,则会引发System.NullReferenceException(对象引用未设置为对象的实例)。调试器告诉我,异常引发线System.Windows.Threading.Dispatcher.Run();。但是,如果我不尝试将地图居中并且不将地图设置为“空中”模式,则一切正常。我应该怎么做才能从后台线程调用WPF窗口并在运行时更改Bing Map的属性,而不会有任何问题? 我已经检查过,如果WPF窗口从主UI线程被调用,那么一切都会正常工作。 有趣的是,如果我关闭WPF窗口并再次按下按钮,新的WPF窗口通常会显示Bing地图,并且不会抛出System.NullReferenceException

+0

为什么要在新线程中显示新窗口?为什么不在创建新窗口时通过Dispatcher调用回主WPF UI线程? – 2014-10-28 19:50:30

+0

好吧,主线程如何知道后台线程何时完成其计算?这不需要用户在后台线程完成后按下其他按钮来显示地图吗? – user3623874 2014-10-28 19:53:34

+0

这取决于Map对象。但最坏的情况是,您在后台线程上运行“计算”操作(即通过任务),然后在操作完成时使用Dispatcher.Invoke()通知主线程。不幸的是,你的代码示例实际上并没有显示这个“计算”操作是如何发生的,所以不可能以特定的方式来回答。 – 2014-10-28 20:15:18

回答

0

我最终在我的一个UI元素上调用了BeginInvoke()。它允许我创建一个创建该UI元素的线程来执行一个我作为参数传递的函数。