Данная статья это конспект из видео в котором создают интерактивную карту в WPF
Для реализации мы будем использовать следующие технологии:
- Prism 8 MVVM framework, и DryLoc контейнер для dependency injection
- .NET Core 6.0, WPF (Windows Presentation Foundation).
Создание проекта можно поделить на следующие этапы:
- Создание и настройка главного окна нашего приложения
- Загрузка и конвертирование SVG карты в xaml файл(с помощью программы Inkscape)
- Настройка триггера для изменения цвета при наведении курсора мыши
- Обработать щелчок мыши, чтобы показать выделенную область
- Прочитать данные из CSV файла.
- Добавление панели свойств для карты
Создание и настройка главного окна нашего приложения
Проект был создан с помощью Prism Template Pack
. Этот пакет шаблонов содержит коллекцию сниппетов, шаблонов элементов и шаблонов проектов которые можно использовать при создании WPF и Xamarin приложений с помощью Prism.
После установки этого пакета шаблонов создаем проект «Prism blank app(WPF)
» и называем его MapPrism
.
Добавим новое view(RuMap.xaml
) и автоматически создается файл RuMapViewModel
в папке ViewModels. Для отображения этого view нужно его зарегистрировать в файле MainWindows.cs
Загрузка и конвертирование SVG карты в xaml файл(с помощью программы Inkscape)
Скачать программу можно ниже по ссылке
Необходимо скачать нужную нам карты с сайта. В нашем случае это карта России
Карту можно выбрать любую, но в формате SVG
Открываем программу Inkscape и выбираем скачанный нами файл svg
На данной карте можно менять названия регионов добавлять дополнительные настройки
После внесения изменений сохраняем документ как «Microsoft XAML(*.xaml)»
Созданный таким образом файл можно добавлять в наш ранее созданный проект в RuMap.xaml.
Настройка триггера для изменения цвета при наведении курсора мыши
Откроем файл RuMap.xaml и добавим следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 |
<UserControl.Resources> <ResourceDictionary> <Style TargetType="{x:Type Path}"> <Setter Property="Fill" Value="#FF7C7C7C"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Fill" Value="Red"/> </Trigger> </Style.Triggers> </Style> </ResourceDictionary> </UserControl.Resources> |
Этот код реализует триггер, который при наведении мыши на область карты подсвечивает её красным цветом.
Обработать щелчок мыши, чтобы показать выделенную область
Для обработки нажатия мышью на область мы будем использовать xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
1 2 3 4 5 6 |
<i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown" > <i:InvokeCommandAction Command="{Binding LeftMouseButtonDown}" PassEventArgsToCommand="True"/> </i:EventTrigger> </i:Interaction.Triggers> |
Таким образом, после клика мыши на объект будет вызываться команда LeftMouseButtonDown
и передавать во ViewModel
выделенный объект.
Добавим в файл RuMapViewModel
свойство SelectedPath
(propp) и команду LeftMouseButtonDown
(cmdg)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public string CountryData { get { return countryData; } set { SetProperty(ref countryData, value); } } private DelegateCommand<object> _leftMouseButtonDown; public DelegateCommand<object> LeftMouseButtonDown => _leftMouseButtonDown ?? (_leftMouseButtonDown = new DelegateCommand<object>(ExecuteLeftMouseButtonDown)); void ExecuteLeftMouseButtonDown(object obj) { if (!(obj is MouseEventArgs margs)) return; if (!(margs.OriginalSource is Shps.Path spth)) return; SelectedPath = spth.Name; } |
Прочитать данные из CSV файла.
Создадим метод, который будет подгружать данные о наших регионах. В моем случае это region.csv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
List<string[]> ReadCsvFileAsync(string filePath) { var data = new List<string[]>(); using (var sr = new StreamReader(filePath)) { string line; while ((line = sr.ReadLine()) != null) { string[] values = line.Split(','); data.Add(values); } } return data; } |
И метод который преобразующий массив в строку
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
String BuildRegionInfo(string region_code) { string[] region = regionCsv.Where(a => a[10] == region_code).FirstOrDefault(); if (region == null) return null; try { StringBuilder sbuilder = new StringBuilder(); sbuilder.AppendLine("Name".PadRight(20) + " : " + region[0]); sbuilder.AppendLine("Type".PadRight(20) + " : " + region[1]); sbuilder.AppendLine("Name with type".PadRight(20) + " : " + region[2]); sbuilder.AppendLine("Federal district".PadRight(20) + " : " + region[3]); sbuilder.AppendLine("Timezone".PadRight(20) + " : " + region[11]); sbuilder.AppendLine("Geoname code".PadRight(20) + " : " + region[12]); return sbuilder.ToString(); } catch (Exception) { //In case of exception, only send raw data. return null; } } |
И нужно придумать как приложение будет подключаться к этим данным
Добавление панели свойств для карты
В файле RuMap.xaml
добавим поле для отображении информации о регионе
1 2 3 4 5 6 7 8 9 10 11 |
<StackPanel Grid.Column="1" Width="250"> <TextBlock Text="{Binding SelectedPath}" Foreground="Red" FontSize="16"/> <Border CornerRadius="15" Padding="10" Background="White" Margin="15,50,15,15" RenderTransformOrigin="0.5,0.5"> <Border.Effect> <DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="LightGray"/> </Border.Effect> <TextBlock Text="{Binding CountryData}" TextWrapping="Wrap" Foreground="DarkSlateGray" FontSize="15"/> </Border> </StackPanel> |
Во ViewModel добавим свойство RegionData
и в метод ExecuteLeftMouseButtonDown
добавим метод BuildCountryInfo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private string countryData; public string CountryData { get { return countryData; } set { SetProperty(ref countryData, value); } } void ExecuteLeftMouseButtonDown(object obj) { if (!(obj is MouseEventArgs margs)) return; if (!(margs.OriginalSource is Shps.Path spth)) return; SelectedPath = spth.Name; CountryData = BuildCountryInfo(spth.Name); } |
Таким образом у нас получилась интерактивная карта
Спасибо, единственное не понятно содержимое region.csv
region.csv скачал с https://github.com/hflabs/region/blob/master/region.csv