2015-11-03 50 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”视图模型属性。 –