我有这样的情况:我正在构建一个.net Maui智能手机体育应用程序,它可以获取跑步活动的经纬度列表(新的Location类),并在Map中绘制一条线(polyline)来显示路线。我可以从数据库中获取练习列表,也可以在Map中绘制折线,问题是我不能同时做这两件事,因为我不知道如何在ViewModel类中绑定Map函数。
下面是ExercisePage.xaml的xaml代码:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DoradSmartphone.Views.ExercisePage"
xmlns:model="clr-namespace:DoradSmartphone.Models"
xmlns:viewmodel="clr-namespace:DoradSmartphone.ViewModels"
xmlns:maps="clr-namespace:Microsoft.Maui.Controls.Maps;assembly=Microsoft.Maui.Controls.Maps"
xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials"
x:DataType ="viewmodel:ExerciseViewModel"
Title="{Binding Title}">
<Grid Padding="5" Margin="5" RowSpacing="5" ColumnSpacing="3">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="150"/>
</Grid.RowDefinitions>
<maps:Map Grid.Row="0" x:Name="routeMap" VerticalOptions="CenterAndExpand" Grid.ColumnSpan="3" HeightRequest="400" IsZoomEnabled="False" IsEnabled="False">
<x:Arguments>
<MapSpan>
<x:Arguments>
<sensors:Location>
<x:Arguments>
<x:Double>38.744418137669875</x:Double>
<x:Double>-9.128544160596851</x:Double>
</x:Arguments>
</sensors:Location>
<x:Double>0.7</x:Double>
<x:Double>0.7</x:Double>
</x:Arguments>
</MapSpan>
</x:Arguments>
</maps:Map>
<CarouselView ItemsSource="{Binding Exercises}" Grid.Row="1" PeekAreaInsets="100">
<CarouselView.ItemTemplate>
<DataTemplate x:DataType="model:Exercise">
<Frame HeightRequest="90" Margin="5">
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:ExerciseViewModel}}, Path=ExerciseDetailsCommand}
" CommandParameter="{Binding .}"></TapGestureRecognizer>
</Frame.GestureRecognizers>
<HorizontalStackLayout Padding="10" Spacing="5" >
<Label Text="{Binding Id}"></Label>
<Label Text="{Binding Date}"></Label>
</HorizontalStackLayout>
</Frame>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</Grid>
</ContentPage>
正如你所看到的,我把我的Map名声明为routeMap,第一个位置只是从某处开始。我还为CarouselView中的练习列表的DataBinding声明了我的模型和视图模型。点击功能工作正常,并带我到一个名为ExerciseDetailsPage的新视图。
这是ExercisePage.xaml.cs背后的代码
using DoradSmartphone.Models;
using DoradSmartphone.ViewModels;
using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
namespace DoradSmartphone.Views;
public partial class ExercisePage : ContentPage
{
public ExercisePage(ExerciseViewModel exerciseViewModel)
{
InitializeComponent();
BindingContext = exerciseViewModel;
}
private void OnTapGestureRouteUpdate(object sender, EventArgs e)
{
var route = new Polyline
{
StrokeColor = Colors.Red,
StrokeWidth = 12,
Geopath =
{
new Location(38.70061856336034 , -8.957381918676203 ),
new Location(38.70671683905933 , -8.945225024701308 ),
new Location(38.701985630081595, -8.944503277546072 ),
new Location(38.701872978433386, -8.940750192338834 ),
new Location(38.71054663609023 , -8.939162348597312 ),
new Location(38.717755109243214, -8.942193686649311 ),
new Location(38.7435419727561 , -8.928480490699792 ),
new Location(38.78327379379296 , -8.880556478454272 ),
new Location(38.925473761602376, -8.881999972299806 ),
new Location(38.93692729913667 , -8.869585920414709 ),
new Location(38.93493556584553 , -8.86536198145887 )
}
};
routeMap.MoveToRegion(
MapSpan.FromCenterAndRadius(
new Location(38.93479161472441, -8.865352563545757), Distance.FromMiles(1)));
// Add the polyline to the map
routeMap.MapElements.Add(route);
}
}
如果我将实际的点击功能更改为这个点击事件,我可以在Map中绘制任何线条和其他内容,因为我可以读取xaml代码中定义的map名称。但是在这个codebehind类中,我无法访问ViewModel、Services或Model类。
这是我的ExerciseViewModel.cs类:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DoradSmartphone;
using DoradSmartphone.Models;
using DoradSmartphone.Services;
using DoradSmartphone.Views;
using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using System.Collections.ObjectModel;
namespace DoradSmartphone.ViewModels
{
public partial class ExerciseViewModel : BaseViewModel
{
private readonly ExerciseService exerciseService;
public ObservableCollection<Exercise> Exercises { get; private set; } = new();
public ExerciseViewModel(ExerciseService exerciseService)
{
Title = "Training Routes";
this.exerciseService = exerciseService;
_ = GetExerciseList();
}
[ObservableProperty]
bool isRefreshing;
async Task GetExerciseList()
{
if (IsLoading) return;
try
{
IsLoading = true;
if (Exercises.Any()) Exercises.Clear();
var exercices = exerciseService.GetExercises();
foreach (var exercise in exercices) Exercises.Add(exercise);
} catch(Exception ex) {
Console.WriteLine(ex.ToString());
await Shell.Current.DisplayAlert("Error", "Failed to retrieve the exercice list", "Ok");
}
finally {
IsLoading = false;
isRefreshing= false;
}
}
[RelayCommand]
async Task ExerciseDetails(Exercise exercise)
{
if(exercise == null) return;
var routes = GetLocations(exercise.Id);
DrawRoutes(routes);
}
public List<Location> GetLocations(int exerciseId)
{
if (exerciseId == 1)
{
return new List<Location>
{
new Location(35.6823324582143, 139.7620853729577),
new Location(35.679263477092704, 139.75773939496295),
new Location(35.68748054650018, 139.761486207315),
new Location(35.690745005825136, 139.7560362984393),
new Location(35.68966608916097, 139.75147199952355),
new Location(35.68427128680411, 139.7442168083328)
};
}
else if (exerciseId == 2)
{
return new List<Location>
{
new Location(35.6823324582143, 139.7620853729577),
new Location(35.679263477092704, 139.75773939496295),
new Location(35.68748054650018, 139.761486207315),
new Location(35.690745005825136, 139.7560362984393),
new Location(35.68966608916097, 139.75147199952355),
new Location(35.68427128680411, 139.7442168083328)
};
}
else
{
return new List<Location>
{
new Location(35.6823324582143, 139.7620853729577),
new Location(35.679263477092704, 139.75773939496295),
new Location(35.68748054650018, 139.761486207315),
new Location(35.690745005825136, 139.7560362984393),
new Location(35.68966608916097, 139.75147199952355),
new Location(35.68427128680411, 139.7442168083328)
};
}
}
private void DrawRoutes(List<Location> routes)
{
var polylines = new Polyline
{
StrokeColor = Colors.Red,
StrokeWidth = 12,
};
foreach(var route in routes)
{
polylines.Geopath.Add(route);
}
routeMap.MoveToRegion(
MapSpan.FromCenterAndRadius(
routes.FirstOrDefault(), Distance.FromMiles(1)));
// Add the polyline to the map
routeMap.MapElements.Add(polylines);
}
}
}
这个类继承了继承ObservableObject的BaseViewModel,并且具有所有其他类的一些公共属性。在ExerciseViewModel中,我的RelayCommand与捕获锻炼对象并添加路线的tap特性相关,但我无法访问routeMap对象。我也尝试在我的viewmodel类中声明一个Map类,但是我总是得到错误,我不能创建一个静态类的示例。
这是我的MauiProgram.cs,以防出现问题:
using DoradSmartphone.Data;
using DoradSmartphone.Services;
using DoradSmartphone.ViewModels;
using DoradSmartphone.Views;
namespace DoradSmartphone;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiMaps()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
builder.Services.AddSingleton<DatabaseConn>();
builder.Services.AddScoped<IRepository, DatabaseConn>();
builder.Services.AddSingleton<MainPage>();
builder.Services.AddSingleton<UserPage>();
builder.Services.AddSingleton<LoginPage>();
builder.Services.AddSingleton<LoadingPage>();
builder.Services.AddSingleton<ExercisePage>();
builder.Services.AddSingleton<DashboardPage>();
builder.Services.AddSingleton<ExerciseDetailsPage>();
builder.Services.AddSingleton<UserService>();
builder.Services.AddSingleton<LoginService>();
builder.Services.AddSingleton<ExerciseService>();
builder.Services.AddSingleton<DashboardService>();
builder.Services.AddSingleton<UserViewModel>();
builder.Services.AddSingleton<LoginViewModel>();
builder.Services.AddSingleton<LoadingViewModel>();
builder.Services.AddSingleton<ExerciseViewModel>();
builder.Services.AddSingleton<DashboardViewModel>();
builder.Services.AddTransient<ExerciseDetailsViewModel>();
return builder.Build();
}
}
感谢您的评分
1条答案
按热度按时间kwvwclae1#
不幸的是,
MapElements
不是可绑定的属性。但是,您可以通过以下几种方法来解决这个问题例如,在VM中创建一个返回路由数据的公共方法
然后在后面的代码中,首先创建对VM的类引用
则您的代码可以从VM获取更新Map所需的数据