2010-11-10 4 views
1

J'essaye de faire un projet d'école où nous devons créer une application Silverlight qui utilise la carte bing comme une sorte d'éditeur de carte pour le placement des stations payantes pour les voitures.Bing Maps et MVVM

Exemple: Bing map

Il y a des exigences, il doit prendre en charge le glisser-déposer, et nous devons utiliser MVVM (Model View View-Model). Maintenant, nous avons terminé la fonction de glisser-déposer en ayant un MapLayer avec un tableau d'enfants Image, puis les événements connectés qui permettent de glisser-déposer (voir le code ci-dessous). Mais maintenant, nous sommes confrontés à un problème, comment peut-on brancher un ViewModel à cela, je ne peux tout simplement voir pas :(

Je ne demande pas une solution complète, mais un peu d'aide serait génial.

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 
    } 
} 

Mon code 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> 

Répondre

4

Je déteste pour vous dire cela, mais le code que vous avez déjà écrit ne ressemble en rien WPF ou un code MVVM. vous faites cela d'une manière très WinForms-ish.

It wo pas tellement "convertir" votre code MVVM comme "le refaire" de cette façon.

La première chose que vous voulez demander est, "que devrais-je avoir dans mon modèle?" Évidemment, le modèle consiste en une liste d'objets tels que les maisons et les centrales électriques. Chacun de ces objets a au moins un type et un emplacement.

Je vous recommande de définir un type de classe MappableObject et d'utiliser une ObservableCollection dans votre modèle pour stocker vos objets mappables.

Votre contrôle principal doit évidemment être un ItemsControl qui utilise un Canvas pour son ItemsPanel. Le modèle d'élément doit définir Canvas.Left et Canvas.Top pour correspondre à l'emplacement de l'élément. Vous auriez besoin d'un convertisseur pour convertir un emplacement en un point.

Maintenant, si ItemsControl a son ItemsSource lié à votre ObservableCollection, chaque fois qu'un objet mappable est ajouté à la collection, il apparaîtra dans son emplacement. Chaque fois que vous changez de lieu, il se déplacera vers le nouvel emplacement sur l'écran.

Vous aurez besoin de quelque chose pour gérer les événements de glisser et afficher le curseur. J'utiliserais le code à peu près comme ce que vous avez déjà, sauf le mettre dans un UserControl qui est utilisé dans votre ItemTemplate. Il peut trouver son conteneur et l'utiliser pour mapper les coordonnées de déplacement afin de cartographier les emplacements. Au fur et à mesure que le glissement progresse, il peut mettre à jour la propriété location de MappableObject. N'oubliez pas de transformer toutes les coordonnées sur la carte en utilisant TransformToVisual au lieu d'utiliser les coordonnées locales pour le contrôle. Pour obtenir la bonne image pour un objet, utilisez un convertisseur: Votre modèle sait quel type d'objet il est, et vous pouvez nommer vos fichiers .png pour que votre convertisseur puisse facilement récupérer le bon .png de votre Répertoire d'images en construisant l'URL directement à partir du type d'objet. J'espère que ces suggestions vous aideront à avancer dans la bonne direction. Faire cela dans WPF en utilisant MVVM est assez simple et beaucoup plus propre que de faire l'ancienne façon WinForms, mais vous devrez utiliser beaucoup de nouvelles techniques auxquelles vous n'avez pas l'habitude, donc il y aura une courbe d'apprentissage.

Meilleurs voeux pour votre succès.

Questions connexes