2010-11-10 77 views
1

我正在尝试创建一个学校项目,我们将创建一个Silverlight应用程序,该应用程序使用bing地图作为一种地图编辑器来放置汽车的收费站。Bing Maps和MVVM

例子: Bing map

有一些要求,它必须支持鼠标拖放及我们必须使用MVVM(模型视图视图模型)。现在我们已经完成了拖放功能,让MapLayer带有一个Image子数组,然后连接启用拖放的事件(请参阅下面的代码)。但是,现在我们面临的一个问题,我们如何可以挂钩一个ViewModel到这一点,我只是简单地不能看到它:(

我不是要求一个完整的解决方案,但一些帮助将是巨大的。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Media.Imaging; 
using System.Windows.Shapes; 
using System.IO; 
using Microsoft.Maps.MapControl; 

namespace BingMapDragDrop 
{ 
    public partial class MainPage : UserControl 
    { 
     private MapAddType AddType = MapAddType.None; 
     private Location _myhome = new Location(55.6686512716393, 12.5481431962938, 0); 

     private MapLayer EndNodeLayer; 
     private double HideEndNodeLayer = 10.0; 
     private MapLayer EndNodeIntermediatedLayer; 
     private double HideEndNodeIntermediatedLayer = 10.0; 
     private MapLayer RootNodeLayer; 
     private double HideRootNodeLayer = 0.0; 
     private MapLayer RootNodeIntermediatedLayer; 
     private double HideRootNodeIntermediatedLayer = 5.0; 

     public MainPage() 
     { 
      EndNodeLayer = new MapLayer(); 
      EndNodeIntermediatedLayer = new MapLayer(); 
      RootNodeLayer = new MapLayer(); 
      RootNodeIntermediatedLayer = new MapLayer(); 


      InitializeComponent(); 
      BingMap.SetView(_myhome, 15); 
      BingMap.ViewChangeOnFrame += new EventHandler<MapEventArgs>(BingMap_ViewChangeOnFrame); 

      // Adding the layers 
      BingMap.Children.Add(EndNodeIntermediatedLayer); 
      BingMap.Children.Add(EndNodeLayer); 
      BingMap.Children.Add(RootNodeIntermediatedLayer); 
      BingMap.Children.Add(RootNodeLayer); 
     } 

     private void AddEndNode(Location location, MapAddType type) 
     { 
      string url; 

      if (type == MapAddType.Home) 
       url = "Images/Home.png"; 
      else if (type == MapAddType.HomeWithChargingSpot) 
       url = "Images/HomeWithChargingSpot.png"; 
      else if (type == MapAddType.Workplace) 
       url = "Images/Workplace.png"; 
      else if (type == MapAddType.WorkplaceWithChargingSpot) 
       url = "Images/WorkplaceWithChargingSpot.png"; 
      else if (type == MapAddType.PublicChargningSpot) 
       url = "Images/PublicChargningSpot.png"; 
      else if (type == MapAddType.FastChargingStation) 
       url = "Images/FastChargingStation.png"; 
      else 
       return; 

      var image = new Image 
      { 
       Source = new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute)), 
       Width = 50, 
       Height = 50 
      }; 
      AddImageToLayerAsDragAbleObject(image, location, EndNodeLayer); 
     } 
     private void AddPowerPlant(Location location) 
     { 
      var image = new Image 
      { 
       Source = new BitmapImage(new Uri("Images/Powerplant-New.png", UriKind.RelativeOrAbsolute)), 
       Width = 50, 
       Height = 50 
      }; 
      AddImageToLayerAsDragAbleObject(image, location, EndNodeLayer); 
     } 

     #region Bing Map Events, not related to D&D 
     // Some events dose not exists so we need to make some our self. 
     private double bingZoom = 0.0; 
     void BingMap_ViewChangeOnFrame(object sender, MapEventArgs e) 
     { 
      if (BingMap.ZoomLevel != bingZoom) 
      { 
       bingZoom = BingMap.ZoomLevel; 
       BingMapZoomLevelChanged(sender, e); 
      } 
     } 

     private void BingMap_Loaded(object sender, RoutedEventArgs e) 
     { 

     } 
     private void BingMap_MouseClick(object sender, MapMouseEventArgs e) 
     { 
      if(AddType == MapAddType.None) 
       return; 

      Location loc; 
      if (!BingMap.TryViewportPointToLocation(e.ViewportPoint, out loc)) 
       return; 

      switch (AddType) 
      { 
       case MapAddType.Powerplant: 
        AddPowerPlant(loc); 
        break; 
       case MapAddType.FastChargingStation: 
       case MapAddType.PublicChargningSpot: 
       case MapAddType.WorkplaceWithChargingSpot: 
       case MapAddType.Workplace: 
       case MapAddType.HomeWithChargingSpot: 
       case MapAddType.Home: 
        AddEndNode(loc, AddType); 
        break; 
      } 

      AddType = MapAddType.None; 
     } 
     private void BingMapZoomLevelChanged(object sender, MapEventArgs e) 
     { 
      if (BingMap.ZoomLevel <= HideEndNodeLayer && EndNodeLayer.Visibility == Visibility.Visible) 
       EndNodeLayer.Visibility = Visibility.Collapsed; 
      else if (BingMap.ZoomLevel > HideEndNodeLayer && EndNodeLayer.Visibility == Visibility.Collapsed) 
       EndNodeLayer.Visibility = Visibility.Visible; 

      if (BingMap.ZoomLevel >= HideEndNodeIntermediatedLayer && EndNodeLayer.Visibility == Visibility.Visible) 
       EndNodeIntermediatedLayer.Visibility = Visibility.Collapsed; 
      else if (BingMap.ZoomLevel > HideEndNodeIntermediatedLayer && EndNodeLayer.Visibility == Visibility.Collapsed) 
       EndNodeIntermediatedLayer.Visibility = Visibility.Visible; 

      if (BingMap.ZoomLevel <= HideRootNodeLayer && EndNodeLayer.Visibility == Visibility.Visible) 
       RootNodeLayer.Visibility = Visibility.Collapsed; 
      else if (BingMap.ZoomLevel > HideRootNodeLayer && EndNodeLayer.Visibility == Visibility.Collapsed) 
       RootNodeLayer.Visibility = Visibility.Visible; 

      if (BingMap.ZoomLevel <= HideRootNodeIntermediatedLayer && EndNodeLayer.Visibility == Visibility.Visible) 
       RootNodeIntermediatedLayer.Visibility = Visibility.Collapsed; 
      else if (BingMap.ZoomLevel > HideRootNodeIntermediatedLayer && EndNodeLayer.Visibility == Visibility.Collapsed) 
       RootNodeIntermediatedLayer.Visibility = Visibility.Visible; 
     } 
     #endregion 

     #region This is where the dragging magic happens 
     private void AddImageToLayerAsDragAbleObject(Image image, Location location, MapLayer mapLayer) 
     { 
      image.MouseLeftButtonDown += new MouseButtonEventHandler(ImageMouseLeftButtonDown); 
      var position = PositionOrigin.Center; 
      mapLayer.AddChild(image, location, position); 
     } 

     private bool _isDragging = false; 
     private Image _dragingObject; 
     private void ImageMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
     { 
      _isDragging = true; 
      // We need to save the object, so we are able to set the location on release 
      _dragingObject = (Image)sender; 

      // Here we add the events, be sure to remove them at release! 
      BingMap.MousePan += new EventHandler<MapMouseDragEventArgs>(BingMapMousePan); 
      BingMap.MouseLeftButtonUp += new MouseButtonEventHandler(BingMapMouseLeftButtonUp); 
      BingMap.MouseMove += new MouseEventHandler(BingMapMouseMove); 
     } 
     // Event that is called when an image is move 
     private void BingMapMouseMove(object sender, MouseEventArgs e) 
     { 
      var map = (Map)sender; 
      if (!_isDragging) return; 
      // The the location of the mouse 
      var mouseMapPosition = e.GetPosition(map); 
      var mouseGeocode = map.ViewportPointToLocation(mouseMapPosition); 

      // Set location 
      MapLayer.SetPosition(_dragingObject, mouseGeocode); 
     } 
     // Event that is called when an image is released 
     private void BingMapMouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
     { 
      // Remove the events 
      BingMap.MousePan -= BingMapMousePan; 
      BingMap.MouseLeftButtonUp -= BingMapMouseLeftButtonUp; 
      BingMap.MouseMove -= BingMapMouseMove; 
      // Disable dragging 
      _isDragging = false; 
     } 
     // Event that is called when the map is panning 
     private void BingMapMousePan(object sender, MapMouseDragEventArgs e) 
     { 
      // We don't want the map to pan if we are dragging 
      if (_isDragging) 
       e.Handled = true; 
     } 
     #endregion 

     #region Menu 
     private void MenuMouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
     { 
      if ((String)((Image)sender).Tag == "Powerplant") 
       AddType = AddType == MapAddType.Powerplant ? MapAddType.None : MapAddType.Powerplant; 

      if ((String)((Image)sender).Tag == "Home") 
       AddType = AddType == MapAddType.Home ? MapAddType.None : MapAddType.Home; 

      if ((String)((Image)sender).Tag == "HomeWithChargingSpot") 
       AddType = AddType == MapAddType.HomeWithChargingSpot ? MapAddType.None : MapAddType.HomeWithChargingSpot; 

      if ((String)((Image)sender).Tag == "Workplace") 
       AddType = AddType == MapAddType.Workplace ? MapAddType.None : MapAddType.Workplace; 

      if ((String)((Image)sender).Tag == "WorkplaceWithChargingSpot") 
       AddType = AddType == MapAddType.WorkplaceWithChargingSpot ? MapAddType.None : MapAddType.WorkplaceWithChargingSpot; 

      if ((String)((Image)sender).Tag == "PublicChargningSpot") 
       AddType = AddType == MapAddType.PublicChargningSpot ? MapAddType.None : MapAddType.PublicChargningSpot; 

      if ((String)((Image)sender).Tag == "FastChargingStation") 
       AddType = AddType == MapAddType.FastChargingStation ? MapAddType.None : MapAddType.FastChargingStation; 
     } 
     #endregion 

     #region Cursor image 

     private bool IsCursorImageSet = false; 

     private void UserControl_MouseMove(object sender, MouseEventArgs e) 
     { 
      PlaceCursorImage(e.GetPosition(this)); 
     } 
     private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
     { 
      PlaceCursorImage(e.GetPosition(this)); 
     } 
     private void PlaceCursorImage(Point location) 
     { 
      if (AddType == MapAddType.None && !IsCursorImageSet) 
       return; 
      if (AddType == MapAddType.None && IsCursorImageSet) 
      { 
       IsCursorImageSet = false; 
       CursorImage.Visibility = Visibility.Collapsed; 
       return; 
      } 

      Canvas.SetTop(CursorImage, location.Y + 5.0); 
      Canvas.SetLeft(CursorImage, location.X + 5.0); 

      if (!IsCursorImageSet) 
      { 
       IsCursorImageSet = true; 

       switch (AddType) 
       { 
        case MapAddType.Powerplant: 
         CursorImage.Source = 
          new BitmapImage(new Uri("Images/Powerplant-New.png", UriKind.RelativeOrAbsolute)); 
         break; 
        case MapAddType.Home: 
         CursorImage.Source = 
          new BitmapImage(new Uri("Images/Home.png", UriKind.RelativeOrAbsolute)); 
         break; 
        case MapAddType.HomeWithChargingSpot: 
         CursorImage.Source = 
          new BitmapImage(new Uri("Images/HomeWithChargingSpot.png", UriKind.RelativeOrAbsolute)); 
         break; 
        case MapAddType.Workplace: 
         CursorImage.Source = 
          new BitmapImage(new Uri("Images/Workplace.png", UriKind.RelativeOrAbsolute)); 
         break; 
        case MapAddType.WorkplaceWithChargingSpot: 
         CursorImage.Source = 
          new BitmapImage(new Uri("Images/WorkplaceWithChargingSpot.png", UriKind.RelativeOrAbsolute)); 
         break; 
        case MapAddType.PublicChargningSpot: 
         CursorImage.Source = 
          new BitmapImage(new Uri("Images/PublicChargningSpot.png", UriKind.RelativeOrAbsolute)); 
         break; 
        case MapAddType.FastChargingStation: 
         CursorImage.Source = 
          new BitmapImage(new Uri("Images/FastChargingStation.png", UriKind.RelativeOrAbsolute)); 
         break; 
        default: 
         return; 
       } 

       CursorImage.Visibility = Visibility.Visible; 
       CursorImage.Width = 40; 
       CursorImage.Height = 40; 
       CursorImage.Stretch = Stretch.Uniform; 
      } 
     } 
     #endregion 
    } 
} 

我的WPF代码

<UserControl x:Class="BingMapDragDrop.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl" 
    mc:Ignorable="d" MouseMove="UserControl_MouseMove" Width="800" Height="600" MouseLeftButtonUp="UserControl_MouseLeftButtonUp"> 
    <Canvas IsHitTestVisible="True"> 
     <StackPanel HorizontalAlignment="Left" Name="stackPanelMenu" Width="75" Margin="0,12,0,12" Canvas.Top="0" Height="588"> 
      <Image Name="imagePowerplant" Stretch="Uniform" Width="35" Source="/BingMapDragDrop;component/Images/Powerplant-New.png" Tag="Powerplant" MouseLeftButtonUp="MenuMouseLeftButtonUp" /> 
      <Image Name="imageHome" Stretch="Uniform" Width="35" Source="/BingMapDragDrop;component/Images/Home.png" Tag="Home" MouseLeftButtonUp="MenuMouseLeftButtonUp" /> 
      <Image Name="imageHomeWithChargingSpot" Stretch="Uniform" Width="35" Source="/BingMapDragDrop;component/Images/HomeWithChargingSpot.png" Tag="HomeWithChargingSpot" MouseLeftButtonUp="MenuMouseLeftButtonUp" /> 
      <Image Name="imageWorkplace" Stretch="Uniform" Width="35" Source="/BingMapDragDrop;component/Images/Workplace.png" Tag="Workplace" MouseLeftButtonUp="MenuMouseLeftButtonUp" /> 
      <Image Name="imageWorkplaceWithChargingSpot" Stretch="Uniform" Width="35" Source="/BingMapDragDrop;component/Images/WorkplaceWithChargingSpot.png" Tag="WorkplaceWithChargingSpot" MouseLeftButtonUp="MenuMouseLeftButtonUp" /> 
      <Image Name="imagePublicChargningSpot" Stretch="Uniform" Width="35" Source="/BingMapDragDrop;component/Images/PublicChargningSpot.png" Tag="PublicChargningSpot" MouseLeftButtonUp="MenuMouseLeftButtonUp" Height="49" /> 
      <Image Name="imageFastChargingStation" Stretch="Uniform" Width="35" Source="/BingMapDragDrop;component/Images/FastChargingStation.png" Tag="FastChargingStation" MouseLeftButtonUp="MenuMouseLeftButtonUp" /> 
     </StackPanel> 
     <m:Map x:Name="BingMap" CredentialsProvider="[Insert credentials here]" Mode="Aerial" Loaded="BingMap_Loaded" MouseClick="BingMap_MouseClick" Canvas.Left="72" Canvas.Top="0" Margin="0" Height="600" Width="728" /> 

     <Image Name="CursorImage" Visibility="Collapsed" IsHitTestVisible="False" Opacity="0.5" /> 
    </Canvas> 
</UserControl> 

回答

4

我不想告诉你这一点,但你已经写的代码看上去一点也不像WPF或MVVM代码。你是在一个非常的WinForms十岁上下的方式这样做。

It wo不要那么“转换”你的代码到MVVM,就像“重做”那样。

你想问的第一件事是,“我应该在我的模型中有什么?”显然,该模型由一系列对象组成,如住宅和发电厂。每个对象都至少有一个类型和一个位置。

我建议您定义某种MappableObject类,并在模型中使用ObservableCollection来存储可映射的对象。

你的主要控件显然应该是一个为其ItemsPanel使用Canvas的ItemsControl。项目模板必须设置Canvas.Left和Canvas.Top以匹配项目的位置。你需要一个转换器将一个位置转换为一个点。

现在,如果您的ItemsControl将其ItemsSource绑定到您的ObservableCollection,则每次将可映射对象添加到集合时,它都将显示在其位置中。任何时候你改变它的位置,它都会移动到屏幕上的新位置。

您需要一些东西来处理拖动事件并显示光标。我会使用与您已有的代码大致相似的代码,除了将它放在ItemTemplate中使用的UserControl中。它可以找到它的容器并使用它来将拖动坐标映射到地图位置。随着拖动的进行,它可以更新MappableObject的位置属性。请记住使用TransformToVisual将所有坐标转换到地图上,而不是使用控件的本地坐标。

要获得正确的图像对象,使用转换器:您的模型知道它是什么类型的对象,并且您可以命名您的.png文件以匹配,以便您的转换器可以轻松地从您的通过直接从对象类型构建Url来映射目录。

我希望这些建议能帮助您朝着正确的方向前进。使用MVVM在WPF中执行此操作比使用旧的WinForms方法更简单,更清洁,但您需要使用大量不习惯的新技术,这样才会有学习曲线。

祝你成功。