2013-03-20 21 views
1

有點難倒在這裏。從TimerCallback函數更新UI線程Windows Phone 8

我有一個TimerCallback每隔10秒觸發一次,其中包含放置在地圖上的Geopoint。我嘗試從定時器回調函數中將這些添加到地圖中,但由於它位於不同的線程中,因此我無法執行此操作。我收到以下錯誤:

類型「System.IO.FileNotFoundException」的異常出現在 mscorlib.ni.dll和管理/本地邊界之前沒有處理。

類型的第一次機會異常「System.UnauthorizedAccessException的」 發生在System.Windows.ni.dll

我將如何能繞過這個?我認爲可能會添加一個NotifyCollectionChanged監聽器,但我仍然有同樣的問題。代碼如下所示。

private ObservableCollection<Bus> _busList; 
    private Timer _timer = null; 
    public ItemViewModel route; 

    public ObservableCollection<Bus> BusList 
    { 
     get { return _busList; } 
     set { _busList = value; } 
    } 
    //public LocationManager locMan = LocationManager.Instance; 
    // Constructor 
    public DetailsPage() 
    { 
     InitializeComponent(); 

     // Sample code to localize the ApplicationBar 
     //BuildLocalizedApplicationBar(); 
    } 

    // When page is navigated to set data context to selected item in list 
    protected override void OnNavigatedTo(NavigationEventArgs e) 
    { 
     route = null; 
     if (DataContext == null) 
     { 
      string selectedIndex = ""; 
      if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex)) 
      { 
       int index = int.Parse(selectedIndex); 
       DataContext = App.ViewModel.Items[index]; 
       route = App.ViewModel.Items[index]; 
       if (_timer == null) 
       { 
        TimerCallback tcb = obtainJSON; 
        _timer = new Timer(tcb, route.RouteID, 0, 10000); 
       } 
       else 
       { 
        _timer.Change(0, 10000); 
       } 
       if (BusList == null) 
       { 
        BusList = new ObservableCollection<Bus>(); 
       } 
       else 
       { 
        BusList.Clear(); 
       } 
       BusList.CollectionChanged += HandleBusAdded; 
      } 
     } 
    } 

    private void HandleBusAdded(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     if (e.Action == NotifyCollectionChangedAction.Reset) 
     { 
      Debug.WriteLine("Everything was cleared"); 
     } 
     else 
     { 
      foreach (Bus item in e.NewItems) 
      { 
       Debug.WriteLine(item.vehicleID); 
       Polygon polygon = new Polygon(); 
       polygon.Points.Add(new Point(0, 0)); 
       polygon.Points.Add(new Point(0, 75)); 
       polygon.Points.Add(new Point(25, 0)); 
       polygon.Fill = new SolidColorBrush(Colors.Blue); 

       // Create a MapOverlay and add marker 
       MapOverlay overlay = new MapOverlay(); 
       overlay.Content = polygon; 
       overlay.GeoCoordinate = new GeoCoordinate(item.lat, item.lng); 
       overlay.PositionOrigin = new Point(0.0, 1.0); 
       MapLayer mapLayer = new MapLayer(); 
       mapLayer.Add(overlay); 
       //mapView.Layers.Add(mapLayer); 

       this.Dispatcher.BeginInvoke(() => 
       { 
        mapView.Layers.Add(mapLayer); 
       }); 
      } 
     } 

    } 

    public void obtainJSON(Object stateInfo) 
    { 

     string url = "http://xxx.xxx.xxx" + stateInfo.ToString(); 
     var client = new WebClient(); 
     client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Decrypt); 
     client.DownloadStringAsync(new Uri(url)); 
    } 

    public void Decrypt(Object sender, DownloadStringCompletedEventArgs e) 
    { 
     if (BusList.Count > 0) 
     { 
      BusList.Clear(); 
     } 
     if (!e.Cancelled && e.Error == null) 
     { 
      var temp = new List<string>(); 
      string[] buses = e.Result.Split('\n'); 
      foreach (string bus in buses) 
      { 
       if (!string.IsNullOrWhiteSpace(bus) && !string.IsNullOrEmpty(bus)) 
       { 
        temp.Add(bus); 
       } 
      } 
      foreach (string item in temp) 
      { 
       string[] busInfo = item.Split(','); 
       Bus newBus = new Bus(busInfo[0], busInfo[1], busInfo[2]); 
       BusList.Add(newBus); 

      } 

      // This is where I initially tried 
      /*Polygon polygon = new Polygon(); 
      polygon.Points.Add(new Point(0, 0)); 
      polygon.Points.Add(new Point(0, 75)); 
      polygon.Points.Add(new Point(25, 0)); 
      polygon.Fill = new SolidColorBrush(Colors.Blue); 

      // Enable marker to be tapped for location information 
      // polygon.Tag = new GeoCoordinate(BusList[0].lat, BusList[0].lng); 

      // Create a MapOverlay and add marker 
      MapOverlay overlay = new MapOverlay(); 
      overlay.Content = polygon; 
      overlay.GeoCoordinate = new GeoCoordinate(BusList[0].lat, BusList[0].lng); 
      overlay.PositionOrigin = new Point(0.0, 1.0); 
      MapLayer mapLayer = new MapLayer(); 
      mapLayer.Add(overlay); 

      this.Dispatcher.BeginInvoke(() => 
      { 
       mapView.Layers.Add(mapLayer); 
      });*/ 
      Debug.WriteLine("Present buses " + BusList[0].vehicleID + ", " + BusList[1].vehicleID); 
     } 
    } 
} 

回答

3

最簡單的事情是將包裹在你obtainJSON方法會發生什麼時分派回UI線程的匿名函數:

public void obtainJSON(Object stateInfo) 
{  
    Dispatcher.BeginInvoke(() => { 
     string url = "http://xxx.xxx.xxx" + stateInfo.ToString(); 
     var client = new WebClient(); 
     client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Decrypt); 
     client.DownloadStringAsync(new Uri(url)); 
    });  
} 

這將意味着一切(包括讓網絡請求和處理響應,因爲WebClient現在執行它對從其調用的線程的回調)發生在UI線程上,因此您不更新綁定到來自不同線程的UI線程的對象。

你也可以嘗試使用DispatcherTimer而不是線程。

您還應該注意處理網絡狀況不佳的情況,請求在超過10秒後超時,並且最終可能會有多個請求正在運行 - 這可能會對您造成影響,也可能不會造成問題。