我的MAUI.net应用程序需要处理几个数据库,一个是不同的球队,另一个是参与者。我想使用选择器,以便在创建/编辑参与者的详细信息时选择其小队,但当我打开参与者查看其详细信息时,我最终得到一个空的选择器。在调试时,当我保存/加载一个参与者时,我可以看到SelectedSquad被正确设置,但是尽管有SelectedItem绑定,它也没有出现在选择器中。
我的参与者视图模型(包含有关参与者的标准信息以及从Squad数据库中提取的信息):
using MatchTracker.Pages;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Web;
namespace MatchTracker.Models.ViewModels
{
public partial class ParticipantDetailsVM : BaseViewModel, IQueryAttributable
{
[ObservableProperty]
Participant currentParticipant;
[ObservableProperty]
Squad selectedSquad;
public ObservableCollection<Squad> SquadsList { get; }
[ObservableProperty]
public string saveButtonText;
public ParticipantDetailsVM()
{
Title = "Participant Details";
SquadsList = new ObservableCollection<Squad>();
}
public async void ApplyQueryAttributes(IDictionary<string, object> query)
{
if (int.TryParse(HttpUtility.UrlDecode(query["id"].ToString()), out int Id))
if (Id == 0)
{
SaveButtonText = "Add Participant";
CurrentParticipant = new Participant { Id = 0 };
}
else
{
SaveButtonText = "Update participant";
CurrentParticipant = await App._ParticipantsDb.GetAsync(Id);
}
}
async Task LoadSquads()
{
try
{
SquadsList.Clear();
var all = await App._SquadsDb.GetAllAsync();
foreach (var item in all)
{
SquadsList.Add(item);
}
SelectedSquad = await App._SquadsDb.GetAsync(CurrentParticipant.SquadId);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
RefreshNeeded = false;
}
}
[RelayCommand]
async Task SaveParticipant()
{
try
{
CurrentParticipant.SquadId = SelectedSquad.Id;
await App._ParticipantsDb.AddAsync(CurrentParticipant);
await Shell.Current.GoToAsync(nameof(ParticipantsListView));
} catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
public async void OnAppearing()
{
await LoadSquads();
}
}
}
我的参与者视图的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="MatchTracker.Pages.ParticipantDetailsView"
xmlns:vm="clr-namespace:MatchTracker.Models.ViewModels"
x:DataType="vm:ParticipantDetailsVM"
Title="{Binding Title}">
<VerticalStackLayout>
<TableView Intent="Data">
<TableRoot>
<TableSection Title="Basic Information">
<EntryCell x:Name="ParticipantNameField" Label="Name" Text="{Binding CurrentParticipant.Name, Mode=TwoWay}" />
</TableSection>
</TableRoot>
</TableView>
<Picker x:Name="ParticipantSquadPicker" Title="Squad" ItemsSource="{Binding SquadsList}" SelectedItem="{Binding SelectedSquad, Mode=TwoWay}" ItemDisplayBinding="{Binding Name}"/>
<Label x:Name="Debug" Text="{Binding CurrentParticipant.SquadId}"/>
<Button x:Name="SaveButton" Text="{Binding SaveButtonText}" Command="{Binding SaveParticipantCommand}"/>
</VerticalStackLayout>
</ContentPage>
链接到上一个XAML文件的.cs文件:
using MatchTracker.Models.ViewModels;
namespace MatchTracker.Pages;
public partial class ParticipantDetailsView : ContentPage
{
public ParticipantDetailsView(ParticipantDetailsVM vm)
{
InitializeComponent();
BindingContext = vm;
}
protected override void OnAppearing()
{
base.OnAppearing();
((ParticipantDetailsVM)BindingContext)?.OnAppearing();
}
}
4条答案
按热度按时间b1zrtrql1#
如果你要使用
ObservableProperty
,把你的领域,使它成为一个属性,你需要使用该属性,即使用它作为一个属性与资本S时,分配您的外地队。因此,您的ViewModel应该看起来像这样才能正确绑定
qpgpyjmq2#
简单解决方案
更改此选项:
变成这样:
注意auto-generated properties赋值的不同之处。您的UI不会更新,因为您将值分配给 backing fields 而不是 properties。只有当你设置属性的值时,observable属性的自动生成的setter方法才会调用
PropertyChanged
事件,当你直接操作后台字段的值时,这不会发生。由于您使用的是
async void
初始化器,因此这些支持字段仅在 * 构造函数完成执行后才被设置,这意味着在此之后不再计算绑定表达式。发生这种情况是因为构造函数总是同步运行的,所以当构造函数已经完成时,您的异步方法仍然在执行,并且更改了后台字段的值,尽管绑定表达式已经执行。因此,在没有收到有关这些更改的通知的情况下,选择器无法知道有关Squad
和Squads
的这些更改值的任何信息。改进方案
与其使用
async void
初始化器方法,不如创建一个Task
,可以await
:然后像这样调用它(例如,在
protected override async void OnAppearing()
方法中):yvgpqqbh3#
请尝试更改类
ParticipantViewModel.cs
的以下代码:到
此外,我们还使用开始以小写字母开头的变量
Squads
,而不是squads
。有关详细信息,请查看文档ObservableObject.。
brccelvz4#
谢谢你的回答,我终于找到了解决问题的方法:
[ObservableProperty]
,但我使用的是后台字段(selectedSquad
)而不是属性本身(SelectedSquad
),将字符串改为小写字母解决了这个问题。我不得不使用
结果表明,即使项目列表和所选项目来自相同的数据库,应用程序也不会将该项目视为列表的一部分。