Карты Bing и MVVM - PullRequest
       9

Карты Bing и MVVM

1 голос
/ 10 ноября 2010

Я пытаюсь сделать школьный проект, в котором мы должны создать приложение Silverlight, которое использует карту Bing в качестве своего рода редактора карт для размещения платных станций для автомобилей.1004 *

Есть некоторые требования, он должен поддерживать перетаскивание, и мы должны использовать MVVM (Model View View-Model).Теперь мы завершили функцию перетаскивания, имея MapLayer с массивом дочерних элементов Image, а затем подключили события, которые позволяют перетаскивание (см. Код ниже).Но теперь мы сталкиваемся с проблемой, как мы можем подключить к этому ViewModel, я просто не вижу ее: (

Я не прошу полного решения, но некоторая помощь была бы полезна.1008 *

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>

1 Ответ

4 голосов
/ 11 ноября 2010

Не хочу вам этого говорить, но код, который вы уже написали, не похож на код WPF или MVVM.Вы делаете это очень WinForms-иш способом.

Это будет не столько "преобразовать" ваш код в MVVM, сколько "переделать" его таким образом.

Первое, что выхочу спросить, "что я должен иметь в моей модели?"Очевидно, что модель состоит из списка объектов, таких как дома и электростанции.Каждый из этих объектов имеет по крайней мере тип и местоположение.

Я рекомендую вам определить некоторый класс MappableObject и использовать ObservableCollection в вашей модели для хранения ваших сопоставляемых объектов.

Ваш главный элемент управленияочевидно, должен быть ItemsControl, который использует Canvas для своей ItemsPanel.Шаблон элемента должен установить Canvas.Left и Canvas.Top в соответствии с местоположением элемента.Вам понадобится конвертер для преобразования из Location в Point.

Теперь, если ваш ItemsControl имеет свой ItemsSource, связанный с ObservableCollection, каждый раз, когда сопоставляемый объект добавляется в коллекцию, он появляется в его Location.Каждый раз, когда вы меняете свое местоположение, оно будет перемещаться на новое место на экране.

Вам понадобится что-то для обработки событий перетаскивания и отображения курсора.Я бы использовал код примерно так же, как у вас, за исключением того, что поместил бы его в UserControl, который используется в вашем ItemTemplate.Он может найти свой контейнер и использовать его для отображения координат перетаскивания на карте.По мере перетаскивания он может обновлять свойство местоположения MappableObject.Не забудьте преобразовать все координаты на карту, используя TransformToVisual вместо использования локальных координат для элемента управления.

Чтобы получить правильное изображение для объекта, используйте конвертер: ваша модель знает, что это за объект, и выможете присваивать имена вашим файлам .png, чтобы ваш конвертер мог легко выбрать нужный файл .png из вашего каталога Images, создав URL-адрес непосредственно из типа объекта.

Надеюсь, что эти предложения помогут вам правильно двигаться.направление.Делать это в WPF с использованием MVVM довольно просто и намного чище, чем старый WinForms, но вам нужно будет использовать множество новых техник, к которым вы не привыкли, так что будет кривая обучения.

Наилучшие пожелания вашего успеха.

...