.NET MAUI 应用程序中的死锁和ConfigureAwait 问题

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

我正在开发 .NET MAUI 应用程序,并遇到了与异步编程相关的潜在死锁问题。我正在寻求有关如何正确使用

ConfigureAwait(false)
以避免死锁并提高性能的建议。

问题描述

在我的应用程序中,我有几个与

ViewModel
交互的异步方法,用于执行数据获取、UI 更新和页面导航等任务。最近,我注意到某些 UI 交互会导致死锁,导致 UI 变得无响应,并且某些操作无限期挂起。

代码详情

这是我的代码的简化版本:

XAML 代码

<ScrollView Orientation="Both" FlowDirection="RightToLeft"
            HorizontalOptions="Start"
            x:Name="ItemsScroller"
            Scrolled="ScrollView_Scrolled"
            HorizontalScrollBarVisibility="Always">
    <VerticalStackLayout>
        <HorizontalStackLayout HeightRequest="48" BackgroundColor="#F5F6F7">
            <!-- Header Labels -->
            <Label Text="کد کالا" Style="{StaticResource LableStyle}" WidthRequest="150" FontAttributes="Bold"/>
            <Label Text="کالا" Style="{StaticResource LableStyle}" WidthRequest="300" FontAttributes="Bold"/>
            <Label Text="نرخ" Style="{StaticResource LableStyle}" WidthRequest="150" FontAttributes="Bold"/>
            <Label Text="مصوبه" Style="{StaticResource LableStyle}" WidthRequest="200" FontAttributes="Bold"/>
            <Label Text="تاریخ مصوبه" Style="{StaticResource LableStyle}" WidthRequest="100" FontAttributes="Bold"/>
            <Label Text="شماره مصوبه" Style="{StaticResource LableStyle}" WidthRequest="100" FontAttributes="Bold"/>
            <Label Text="موجودی" Style="{StaticResource LableStyle}" WidthRequest="100" FontAttributes="Bold"/>
        </HorizontalStackLayout>
        <CollectionView HorizontalScrollBarVisibility="Never" VerticalScrollBarVisibility="Never"
                        VerticalOptions="StartAndExpand"
                        SelectionMode="Multiple" SelectedItems="{Binding SelectedProduct, Mode=TwoWay}"
                        ItemsSource="{Binding Goods}"
                        x:Name="GoodsCollectionView">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <HorizontalStackLayout HeightRequest="48">
                        <!-- Data Template for items -->
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup Name="CommonStates">
                                <VisualState Name="Normal">
                                    <VisualState.Setters>
                                        <Setter Property="BackgroundColor" Value="{Binding Color}"/>
                                    </VisualState.Setters>
                                </VisualState>
                                <VisualState Name="Selected">
                                    <VisualState.Setters>
                                        <Setter Property="BackgroundColor" Value="#C8E6FF"/>
                                    </VisualState.Setters>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <!-- Item Labels -->
                        <Label Text="{Binding ProductCode}" Style="{StaticResource LableStyle}" WidthRequest="150"/>
                        <Line Stroke="#DFDFE0" Y2="40" VerticalOptions="Center"/>
                        <Label Text="{Binding ProductName}" Style="{StaticResource LableStyle}" WidthRequest="300"/>
                        <Line Stroke="#DFDFE0" Y2="40" VerticalOptions="Center"/>
                        <Label Text="{Binding Rate, StringFormat='{0:N0}'}" Style="{StaticResource LableStyle}" WidthRequest="150"/>
                        <Line Stroke="#DFDFE0" Y2="40" VerticalOptions="Center"/>
                        <Label Text="{Binding MosavabeSharh}" Style="{StaticResource LableStyle}" WidthRequest="200"/>
                        <Line Stroke="#DFDFE0" Y2="40" VerticalOptions="Center"/>
                        <Label Text="{Binding MosavabeDate}" Style="{StaticResource LableStyle}" WidthRequest="100"/>
                        <Line Stroke="#DFDFE0" Y2="40" VerticalOptions="Center"/>
                        <Label Text="{Binding MosavabeNo, StringFormat='{0:N0}'}" Style="{StaticResource LableStyle}" WidthRequest="100"/>
                        <Line Stroke="#DFDFE0" Y2="40" VerticalOptions="Center"/>
                        <Label Text="{Binding MojodiVaghee, StringFormat='{0:N0}'}" Style="{StaticResource LableStyle}" WidthRequest="100"/>
                    </HorizontalStackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </VerticalStackLayout>
</ScrollView>

背后代码

private async void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
    if (!onNavigated) return;

    var scrollView = sender as ScrollView;
    if (scrollView != null && scrollView.ScrollY >= scrollView.ContentSize.Height - scrollView.Height)
    {
        await _viewModel.RunIsBusyTaskAsync(async () =>
        {
            start += 49;
            end += 49;
            await _viewModel.UpdateDisplayedItems(true, start, end);
        }).ConfigureAwait(false);
    }
}

视图模型

public async Task UpdateDisplayedItems(bool IsClear, int start, int end)
{
    var result = await GoodToList(new ProductsRequest
    {
        Start = start,
        End = end
    }).ConfigureAwait(false);

    if (result == null || !result.Any())
        return;

    if (IsClear)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            result.ForEach(Goods.Add);

            var productcode = new HashSet<string>(product.Select(c => c.ProductCode));
            var userItemss = result.Where(x => productcode.Contains(x.ProductCode));
            AddRange(SelectedProduct, userItemss);
        });
        return;
    }
    else
    {
        Goods = new ObservableCollection<Good>(result);
        var userItems = result.Where(x => product.Select(c => c.ProductCode).Contains(x.ProductCode));
        SelectedProduct = userItems.Any() ? new ObservableCollection<object>(userItems) : new ObservableCollection<object>();
    }
}

基础视图模型

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Mopups.Services;
using POSApp.Views.Popups;
using System.Collections.ObjectModel;

namespace POSApp.ViewModel
{
    public partial class BaseViewModel : ObservableObject
    {
        private bool IsBusy, SecondIsBusy;
        private Loading loadingPopup;
        public IAsyncRelayCommand<object> OpenBrowserCommand { get; private set; }
        public IAsyncRelayCommand<object> MakePhoneCallCommand { get; private set; }

        public BaseViewModel()
        {
            loadingPopup = new Loading();
            OpenBrowserCommand = new AsyncRelayCommand<object>(OpenBrowserAsync);
            MakePhoneCallCommand = new AsyncRelayCommand<object>(MakePhoneCallAsync);
        }

        public async Task RunIsBusyTaskAsync(Func<Task> awaitableTask)
        {
            if (IsBusy) return;
            IsBusy = true;
            try
            {
                await MopupService.Instance.PushAsync(loadingPopup);
                await awaitableTask();
            }
            catch (Exception) { }
            finally
            {
                if (MopupService.Instance.PopupStack.Any())
                    await MopupService.Instance.PopAsync();
                IsBusy = false;
            }
        }

        public async Task AnimationClicked(object sender)
        {
            if (sender is VisualElement animatable)
            {
                await animatable.ScaleTo(0.75, 100);
                await animatable.ScaleTo(1, 100);
            }
        }

        public void AddRange<T>(ObservableCollection<T> collection, IEnumerable<T> items)
        {
            foreach (var item in items)
            {
                collection.Add(item);
            }
        }
    }
}

问题

尽管在

ConfigureAwait(false)
方法中使用了
UpdateDisplayedItems
,我仍然遇到死锁和 UI 元素无响应的情况。尤其是在处理由 UI 交互触发的异步操作(例如滚动)时,尤其会发生死锁。

问题

  1. 我应该如何有效地使用
    ConfigureAwait(false)
    来避免 .NET MAUI 应用程序上下文中的死锁?
  2. 是否有其他最佳实践来处理 MAUI 应用程序中的异步操作,以防止 UI 冻结并确保流畅的性能?
  3. 我的代码中是否有特定区域可能发生死锁,如何诊断和修复它们?

任何见解或建议将不胜感激。

谢谢!

xamarin xamarin.forms maui maui-community-toolkit
1个回答
0
投票

@movahhed 这个问题你解决了吗?

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