2013-07-23 2 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); 
        } 
    } 
    

С этим все написано, то ваш ViewModel может иметь частный _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

Спасибо Stuart! Я внесу некоторые изменения и отчитаюсь. –

+0

Стюарт отлично работал для iOS. Я попробую сторону дроида, но я думаю, как вы сказали, я просто столкнусь с конкретными проблемами Droid. Большое спасибо, отличный ответ! –

+0

Рад, что это сработало. Был бы * любить *, чтобы увидеть ваши эксперименты с картой дроида, где-то где-то в блоге :) – Stuart

Смежные вопросы