我正在尝试从 .NET MAUI 调用一些 Azure Restful 函数。无论我如何配置等待语句,它们似乎永远不会正确提醒我的线程,以便显示我检索到的数据。
具体来说,我使用 Navigation.PushAsync() 从 ScrollView 打开详细信息页面;
我的页面有一个带有 Observable 集合的 ViewModel。当我创建集合时,我向它发送我想要从云返回的对象的密钥。我格式化 URI 以从 httpClient 执行 GetAsync。我调用 GetAsync,检查状态并将结果作为字符串读取:
try
{
httpHandler.response = await _restHandler.myClient.GetAsync(uri).ConfigureAwait(false);
httpHandler.response.EnsureSuccessStatusCode();
content = await httpHandler.response.Content.ReadAsStringAsync().ConfigureAwait(false);
Items = System.Text.Json.JsonSerializer.Deserialize<List<ProtoArcher>>(content);
if (Items.Count == 1)
{
_protoArcher = Items[0];
}
}
catch (Exception ex)
{
Debug.WriteLine(@"\tError {0}", ex.Message);
}
此代码不会引发任何异常。它最终会在几毫秒内返回我的数据。在其他地方,我在某些 XAML 中将 ContentView 绑定到 ObservableCollection。看起来像这样...
ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DRSMain.Views.RegisterArcher"
Title="RegisterArcher">
<ContentView x:Name="cvMain" Grid.Column="1" Grid.Row="2" Margin="10" >
<StackLayout BindableLayout.ItemsSource="{Binding archers}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Vertical">
<Label Text="Archer Details" VerticalOptions="End" />
<BoxView Color="Black" HeightRequest="3" VerticalOptions="Start" />
<Label Text="First Name" VerticalOptions="End" />
<Entry x:Name="firstName" VerticalOptions="End" Text="{Binding FirstName}"/>
<Label Text="Middle Name" VerticalOptions="End" />
<Entry x:Name="middleName" VerticalOptions="End" Text="{Binding MiddleName}" />
<Label Text="Last Name" VerticalOptions="End" />
<Entry x:Name="lastName" VerticalOptions="End" Text="{Binding LastName}"/>
<Label Text="Date of Birth" VerticalOptions="End"/>
<Entry x:Name="dateOfBirth" VerticalOptions="End" Text="{Binding DateOfBirth}"/>
<Label Text="Email" VerticalOptions="End" />
<Entry x:Name="email" VerticalOptions="End" Text="{Binding Email}"/>
<Label Text="Member Since" VerticalOptions="End" />
<Label x:Name="memberSince" VerticalOptions="End" Text="Today" />
<Label Text="Last Login" VerticalOptions="End" />
<Label x:Name="lastLogin" VerticalOptions="End" Text="Never" />
<Label Text="{Binding ArcherID}" />
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
<BindableLayout.EmptyView>
<StackLayout>
<Label Text="Archer Details" VerticalOptions="End" />
<BoxView Color="Black" HeightRequest="3" VerticalOptions="Start" />
<Label Text="First Name" VerticalOptions="End" />
<Entry VerticalOptions="End" Text="No Data"/>
</StackLayout>
</BindableLayout.EmptyView>
</StackLayout>
</ContentView>
这是我的视图模型,其中包含可观察的弓箭手对象......
namespace DRSMain.ViewModels
{ 公共类RegisterArcherViewModel:INotifyPropertyChanged { 弓箭手 currentArcher; I列出来源;
public ObservableCollection<Archer> archers { get; private set; }
public RegisterArcherViewModel(string anArcherID)
{
currentArcher = new Archer();
source = new ObservableCollection<Archer>();
source.Add(currentArcher);
if (anArcherID != null)
{
currentArcher.ArcherID = anArcherID;
}
archers = new ObservableCollection<Archer>(source);
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
我看到的行为是获取数据的线程从流中丢失(调试器永远看不到它)并且页面呈现,但我获取的数据没有被绑定。当我配置它以使 Observable 集合没有数据时,我得到 EmptyView,但是当数据返回时,我得到非空布局和空白字段。我已经尝试了我能想到的一切。如果我设置一个计时器并检查 ObservableCollection,则在屏幕渲染后,数据就在那里,但它永远不会显示。任何人都可以建议如何让它发挥作用...似乎现在每个人都应该做的事情,调用数据服务并将其显示在页面上...呃....
我尝试强制 OnPropertyChanged,并尝试使用计时器唤醒并检查何时收到数据。然后我尝试更新 UI 并调用 OnPropertyChanged 但无济于事......
虽然 ObservableCollection 在添加/删除时自动更新 UI,但这可能并不总是发生。在更新集合后明确通知弓箭手的属性更改可能会有所帮助:
OnPropertyChanged(nameof(archers));
在主线程上更新UI:当您更新 UI 或 UI 绑定到的底层数据时,请确保使用 Microsoft.Maui.Dispatching.Dispatcher.Dispatch 在主线程上进行这些更新。
try
{
httpHandler.response = await _restHandler.myClient.GetAsync(uri).ConfigureAwait(false);
httpHandler.response.EnsureSuccessStatusCode();
content = await httpHandler.response.Content.ReadAsStringAsync().ConfigureAwait(false);
// Assuming Items is a List<ProtoArcher>
Items = System.Text.Json.JsonSerializer.Deserialize<List<ProtoArcher>>(content);
// Update UI on the main thread
Microsoft.Maui.Dispatching.Dispatcher.Dispatch(() =>
{
if (Items != null && Items.Count > 0)
{
_protoArcher = Items[0]; // Assuming this is how you update your model
// Clear and update your ObservableCollection
archers.Clear(); // Assuming 'archers' is your ObservableCollection in the ViewModel
foreach (var item in Items)
{
archers.Add(item);
}
}
});
}
catch (Exception ex)
{
Debug.WriteLine(@"\tError {0}", ex.Message);
}