訂閱更改集合是數據綁定的基石之一,並且依賴於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
變化的翻譯:類似。
要做到這一點,我們將給予管理者的方法:
創建一個單一的註釋:
private MKAnnotation CreateAnnotation(House house)
{
return new HouseAnnotation(house);
}
添加註釋到地圖(以及在本地查找表)
private void AddAnnotationFor(House house)
{
var annotation = CreateAnnotation(house);
_annotations[house] = annotation;
_mapView.AddAnnotation(annotation);
}
刪除地圖上的註釋(以及從本地查找表)
private void RemoveAnnotationFor(House house)
{
var annotation = _annotations[house];
_mapView.RemoveAnnotation(annotation);
_annotations.Remove(house);
}
做列出了相同的動作:
private void AddAnnotations(IList newItems)
{
foreach (House house in newItems)
{
AddAnnotationFor(house);
}
}
private void RemoveAnnotations(IList oldItems)
{
foreach (House house in oldItems)
{
RemoveAnnotationFor(house);
}
}
迴應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();
}
}
應對整個名單的變化:
// 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方法覆蓋範圍內完成。
謝謝斯圖爾特!我會做出一些改變並回報。 –
斯圖爾特這完美的iOS端。我會嘗試Droid的一面,但我認爲如你所說,我會碰到Droid的具體問題。非常感謝,很好的回答! –
很高興工作。將*愛*看到你的機器人地圖實驗博客:) – Stuart