2015-11-03 52 views
0

我想正確使用MVVM模式。MVVM - 將點添加到地圖

因此,在本例中,我嘗試使用MVVM模型向地圖添加一些點。什麼是最好的方式來做到這一點?

檢視:

<map:Map Name="MyMap"> 
     <i:Interaction.Triggers> 
      <i:EventTrigger EventName="MouseDoubleClick"> 
       <cmd:EventToCommand Command="{Binding DoubleClickCommand}" 
            EventArgsConverter="{StaticResource ConvertToPoint}" 
            PassEventArgsToCommand="True" /> 
      </i:EventTrigger> 
     </i:Interaction.Triggers> 
     <map:MapLayer Name="MyLayer"> 

     </map:MapLayer> 
    </map:Map> 

視圖模型:

public class MainWindowViewModel: ViewModelBase 
{ 
    public RelayCommand<Point> DoubleClickCommand { get; private set; } 

    public MainWindowViewModel() 
    { 
     this.DoubleClickCommand = new RelayCommand<Point>(CreatePoint); 
    } 

    private void CreatePoint(Point arg) 
    { 
     Ellipse pin = new Ellipse(); 
     pin.Width = 3; 
     pin.Height = 3; 
     pin.Fill = Brushes.Blue; 

     Point point = arg; 
     Location PointLocation = MyMap.ViewportPointToLocation(point); 

     MyLayer.AddChild(pin, PointLocation); 
    } 
} 

兩個下列各行是有問題的,因爲使用該視圖的控制:

位置PointLocation = MyMap中.ViewportPointToLocation (點);

MyLayer.AddChild(銷,PointLocation);

我該在哪裏寫這些?在視圖背後的代碼中?

備註:我使用轉換器來獲得一個點作爲函數CreatePoint的參數。

+1

MVVM純粹主義者在視圖中沒有代碼。你只綁定到你的ViewModel,它有你的模型提供的點集合。 – SQLMason

+1

您的ViewModel不必對您的視圖一無所知。這是MVVM打破。正如@丹安德魯斯所說,你必須在視圖模型(或模型)上創建一個映射,並將其綁定到你的視圖。 – Jose

+0

而不是'EventToCommand',你可以創建附加的行爲(使用幾個附加的屬性)。在該行爲的代碼中,您可以訪問所有內容:雙擊事件(訂閱它),映射(將其作爲附加屬性傳遞)和ViewModel(元素的DataContext或將它作爲另一個附加屬性傳遞)。 – Sinatr

回答

0

正如在評論中提到的,最好的辦法是綁定圖釘集合。

Bing地圖WPF控件是不是很寬容,當涉及到Binding。不可能直接綁定到地圖的Children屬性,因此需要採用不同的方法。

首先,創建一個包含您的地圖UserControl,我們就可以使用依賴屬性做幾乎代理綁定Children集合。

<UserControl ... 
     xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF""> 
<Grid> 
    <m:Map CredentialsProvider="Your API Key Here" 
      x:Name="map" 
      MouseDoubleClick="Map_DoubleClicked"/> 
</Grid> 

這裏是後臺代碼:

public partial class BindableMap : UserControl 
{ 
    public ObservableCollection<Pushpin> Pins 
    { 
     get { return (ObservableCollection<Pushpin>)GetValue(PinsProperty); } 
     set { SetValue(PinsProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Pins. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty PinsProperty = 
     DependencyProperty.Register("Pins", typeof(ObservableCollection<Pushpin>), typeof(BindableMap), 
     new PropertyMetadata(null, new PropertyChangedCallback(OnPinsChanged))); 

    private static void OnPinsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     BindableMap map = (BindableMap)d; 

     //If the pin collection changes, then reset the map view. 
     map.ClearMapPoints(); 
     map.SubscribeToCollectionChanged(); 
    } 

    private void ClearMapPoints() 
    { 
     map.Children.Clear(); 
    } 

    private void SubscribeToCollectionChanged() 
    { 
     if (Pins != null) 
      Pins.CollectionChanged += Pins_CollectionChanged; 
    } 

    private void Pins_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     //Remove the old pushpins 
     if (e.OldItems != null) 
      foreach (Pushpin pin in e.OldItems) 
       map.Children.Remove(pin); 

     //Add the new pushpins 
     if (e.NewItems != null) 
      foreach (Pushpin pin in e.NewItems) 
       map.Children.Add(pin); 
    } 

    public BindableMap() 
    { 
     InitializeComponent(); 

     Pins = new ObservableCollection<Pushpin>(); 
    } 

    private void Map_DoubleClicked(object sender, MouseButtonEventArgs e) 
    { 
     //Get the current position of the mouse. 
     Point point = Mouse.GetPosition(map); 

     //Create the pin. 
     Pushpin pin = new Pushpin(); 
     pin.Location = map.ViewportPointToLocation(point); 

     //Add the pin to the map. 
     Pins.Add(pin); 
    } 
} 

這裏要注意的一個事情是,View,在這種情況下,UserControl正在處理雙擊事件。這並不一定需要在視圖模型中處理,因爲我們將使用綁定來代替。

這是一個非常簡單的視圖模型:

public class BindableMapViewModel : PropertyChangedBase 
{ 
    private ObservableCollection<Pushpin> _Pushpins; 

    public ObservableCollection<Pushpin> Pushpins 
    { 
     get { return _Pushpins; } 
     set 
     { 
      _Pushpins = value; 
      NotifyOfPropertyChange(); 
     } 
    } 

    public BindableMapViewModel() 
    { 
     Pushpins = new ObservableCollection<Pushpin>(); 
    } 
} 

現在,所有剩下的就是用你的UserControl在父WindowPushpins視圖模型集合綁定到Pins依賴項屬性。它看起來像這樣:

<map:BindableMap Pins="{Binding Pushpins}"/> 

而且你有它。

+0

有趣的方法。但是對於MVVM的概念,一個用戶控件必須有一個視圖模型關聯與否?我看到很多創建用戶控件(例如MasterView和DetailView)的人在主窗口中使用並將其與視圖模型(例如MasterViewModel和DetailViewModel)綁定。我們必須做什麼或不做什麼? – profou

+0

沒有法律規定您應該在何時何地創建視圖模型。這實際上取決於您的視圖結構以及您如何使用用戶控件。如果爲'UserControl'創建一個新的視圖模型是有意義的,比如master-detail視圖,那麼就這樣做。在我的例子中,我的控件完全沒有視圖模型,而是將其「Pins」依賴屬性綁定到「Pushpins」視圖模型屬性。 –