我在 .NET MAUI 中使用 httpClient.GetAsync 调用 Rest 服务时遇到问题

问题描述 投票:0回答:1

我正在尝试从 .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 但无济于事......

.net asynchronous httpclient maui datatemplate
1个回答
0
投票

虽然 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);
}

© www.soinside.com 2019 - 2024. All rights reserved.