2010-11-10 79 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方法更簡單,更清潔,但您需要使用大量不習慣的新技術,這樣纔會有學習曲線。

祝你成功。