2013-07-23 72 views
4

可以說我有一個包含屬性「註解」的MapView。要在MapView上獲得註釋,您必須使用AddAnotation或AddAnotations。使用MvvmCross如何將註釋列表綁定到MapView?

public class SiteItems 
{ 
    public string Title { get; set; } 
    public string SubTitle { get; set; } 

    public string Phone { get; set; } 
    public string Address { get; set; } 
    public string Url { get; set; } 

    public double Latitude { get; set; } 
    public double Longitude { get; set; } 
} 

然後,我有一個ViewModel的:

public class SiteViewModel : MvxViewModel 
{ 

    private IObservableCollection<Models.SiteItems> _siteItems; 
    public IObservableCollection<Models.SiteItems> SiteItems { 
     get{ return _siteItems; } 
     set{ _siteItems = value; 
      RaisePropertyChanged (() => SiteItems); 
     } 
    } 
} 

我也有一個轉換器,它會SiteItem轉換爲MKAnnotation

所以我想我的問題是我怎麼綁定這樣的事情,因爲我們不能直接綁定到「註解」屬性?我綁定到一個命令?

感謝和任何幫助表示讚賞!

回答

5

訂閱更改集合是數據綁定的基石之一,並且依賴於INotifyCollectionChanged界面的一些知識。

在MvvmCross源代碼中,有幾個示例類顯示瞭如何訂閱集合及其更改通知 - 例如, MvxViewGroupExtensions.cs在Droid和MvxTableViewSource.cs在觸摸

核心該技術是創建一個或Adapter對象Source監聽更改或者在整個列表或列表和這需要相應地動作的部分。

相同類型的方法適用於具有多個 - 但標記的地圖 - 雖然我們還沒有任何輔助類。


而實際上不必在Mac或iOS設備來伸手,這裏大致我會帶創建一個包裝的步驟...

假設我有一個模型對象,如:

public class House 
{ 
    public double Lat { get; set; } 
    public double Lng { get; set; } 
    public string Name { get; set; } 
} 

裏面像一個ViewModel:

public class FirstViewModel : MvxViewModel 
{ 
    public ObservableCollection<House> HouseList { get; set; } 
} 

完成這一操作,然後在視圖我們可以創建一個註解類爲每個房子 - 例如所顯示的地圖上

public class HouseAnnotation : MKAnnotation 
{ 
    public HouseAnnotation(House house) 
    { 
     // Todo - the details of actually using the house here. 
     // in theory you could also data-bind to the house too (e.g. if it's location were to move...) 
    } 

    public override CLLocationCoordinate2D Coordinate { get; set; } 
} 

然後我們可以創建一個HouseAnnotationManager誰的責任是管理被映射到註釋變化的HouseList變化的翻譯:類似。

要做到這一點,我們將給予管理者的方法:

  1. 創建一個單一的註釋:

    private MKAnnotation CreateAnnotation(House house) 
    { 
        return new HouseAnnotation(house); 
    } 
    
  2. 添加註釋到地圖(以及在本地查找表)

    private void AddAnnotationFor(House house) 
    { 
        var annotation = CreateAnnotation(house); 
        _annotations[house] = annotation; 
        _mapView.AddAnnotation(annotation); 
    } 
    
  3. 刪除地圖上的註釋(以及從本地查找表)

    private void RemoveAnnotationFor(House house) 
    { 
        var annotation = _annotations[house]; 
        _mapView.RemoveAnnotation(annotation); 
        _annotations.Remove(house); 
    } 
    
  4. 做列出了相同的動作:

    private void AddAnnotations(IList newItems) 
    { 
        foreach (House house in newItems) 
        { 
         AddAnnotationFor(house); 
        } 
    } 
    
    private void RemoveAnnotations(IList oldItems) 
    { 
        foreach (House house in oldItems) 
        { 
         RemoveAnnotationFor(house); 
        } 
    } 
    
  5. 迴應INotifyCollection變化:

    private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
        switch (e.Action) 
        { 
         case NotifyCollectionChangedAction.Add: 
          AddAnnotations(e.NewItems); 
          break; 
         case NotifyCollectionChangedAction.Remove: 
          RemoveAnnotations(e.OldItems); 
          break; 
         case NotifyCollectionChangedAction.Replace: 
          RemoveAnnotations(e.OldItems); 
          AddAnnotations(e.NewItems); 
          break; 
         case NotifyCollectionChangedAction.Move: 
          // not interested in this 
          break; 
         case NotifyCollectionChangedAction.Reset: 
          ReloadAllAnnotations(); 
          break; 
         default: 
          throw new ArgumentOutOfRangeException(); 
        } 
    } 
    
  6. 應對整個名單的變化:

    // MvxSetToNullAfterBinding isn't strictly needed any more 
    // - but it's nice to have for when binding is torn down 
    [MvxSetToNullAfterBinding] 
    public virtual IEnumerable<House> ItemsSource 
    { 
        get { return _itemsSource; } 
        set { SetItemsSource(value); } 
    } 
    
    protected virtual void SetItemsSource(IEnumerable<House> value) 
    { 
        if (_itemsSource == value) 
         return; 
    
        if (_subscription != null) 
        { 
         _subscription.Dispose(); 
         _subscription = null; 
        } 
        _itemsSource = value; 
        if (_itemsSource != null && !(_itemsSource is IList)) 
         MvxBindingTrace.Trace(MvxTraceLevel.Warning, 
               "Binding to IEnumerable rather than IList - this can be inefficient, especially for large lists"); 
    
        ReloadAllAnnotations(); 
    
        var newObservable = _itemsSource as INotifyCollectionChanged; 
        if (newObservable != null) 
        { 
         _subscription = newObservable.WeakSubscribe(OnItemsSourceCollectionChanged); 
        } 
    } 
    

有了這一切寫的,那麼你的視圖模型可以有一個私人_manager領域,可以創建和數據綁定它:

 _manager = new HouseAnnotationManager(myMapView); 

     var set = this.CreateBindingSet<FirstView, FirstViewModel>(); 
     set.Bind(_manager).To(vm => vm.HouseList); 
     set.Apply(); 

總體而言,這可能看起來像:https://gist.github.com/slodge/6070386

聲明:該代碼尚未編譯,更不用說運行了,但方法基本正確(我認爲)

注:如果這樣做/不能與某些固定的工作,我很喜歡它提交回MVX社區爲樣本;)


相同的基本方法也應該在工作Android - 儘管在Android中,您還必須與Ant,Google Play v2以及所有爵士樂進行戰鬥。


如果您想進行進一步的地圖操作 - 例如,更改地圖中心並在添加房屋時進行縮放,那麼顯然可以在管理器中的AddAnnotation方法覆蓋範圍內完成。

+0

謝謝斯圖爾特!我會做出一些改變並回報。 –

+0

斯圖爾特這完美的iOS端。我會嘗試Droid的一面,但我認爲如你所說,我會碰到Droid的具體問題。非常感謝,很好的回答! –

+0

很高興工作。將*愛*看到你的機器人地圖實驗博客:) – Stuart