在Xamarin C#中向UI添加网格时保持响应性UI

smtd7mpg  于 2022-12-25  发布在  C#
关注(0)|答案(1)|浏览(107)

我用C#编写了一个Xamarin应用程序,它可以注册条形码扫描。拣选器收集物品,扫描它们,然后为客户把它们放进盒子里。
在应用程序中,选择器可以查看每个框中的所有文章。他所要做的就是切换页面上的开关。动态地为每个框创建一个包含文章的网格,并添加到UI中。这种加载需要大量时间,经常超时或不完整。我试图通过使用async/await使UI更具响应性,我想看到的是,这些框可以更快地加载,并在UI上逐个显示,而不是在最后显示。有人能帮我吗?
XAML:

<ContentPage Title="Box" x:Name="cp2">
        <StackLayout Orientation="Vertical" HeightRequest="20">
            <StackLayout Orientation="Horizontal" Margin="0" Spacing="0">
                <Label VerticalOptions="Center" Text="Boxnr:"/>
                <Entry x:Name="txtBoxNr" VerticalOptions="Center" HorizontalOptions="StartAndExpand" WidthRequest="200" 
                       Text="{Binding CurrBoxNr}" FontSize="Small" IsEnabled="{Binding BoxNrEnabled}" Completed="txtBoxNr_Completed"/>
            </StackLayout>
            <StackLayout x:Name="txtOverviewTitle" Orientation="Vertical" Margin="0,10,0,0" Spacing="0" IsVisible="False">
                <StackLayout Orientation="Horizontal" Margin="0,0,0,0" Spacing="0" BackgroundColor="Maroon">
                    <Label VerticalOptions="Start" HorizontalOptions="FillAndExpand"
                           Text="Scan overview" FontSize="22" TextColor="White" HorizontalTextAlignment="Center"/>
                    <Switch x:Name="swOverview" VerticalOptions="Center" Toggled="swOverview_Toggled" IsToggled="False"/>
                </StackLayout>
                <StackLayout x:Name="Loader" Orientation="Vertical" IsVisible="false">
                    <Label x:Name="message1" Text="Loading overview. Please wait..." TextColor="Maroon" IsVisible="false"/>
                    <Label x:Name="message2" Text="Closing overview. Please wait..." TextColor="Maroon" IsVisible="false"/>
                    <ActivityIndicator x:Name="ailoader" Color="Maroon" IsRunning="false"/>
                </StackLayout>
                <Label x:Name="txtUsedBoxes" Margin="10,10,10,5" VerticalOptions="Start" Text="" IsVisible="false"/>
                <BoxView x:Name="bvLine" HeightRequest="1" HorizontalOptions="FillAndExpand" VerticalOptions="End" BackgroundColor="Maroon" IsVisible="false"/>
            </StackLayout>
            <ScrollView x:Name="scrloverview">
                <StackLayout x:Name="Overview" Orientation="Vertical" IsVisible="false"/>
            </ScrollView>
        </StackLayout>
    </ContentPage>

XAML.cs:

private void swOverview_Toggled(object sender, ToggledEventArgs e)
        {
            if (e.Value == true)
                GetOverview();
            else
                RemoveOverview();
        }

private async void GetOverview()
        {           
            message1.IsVisible     = true;
            ailoader.IsRunning     = true;
            Loader.IsVisible       = true;

            #region 1. Clear all children under the StackLayout
            Overview.Children.Clear();           
            #endregion

            #region 2. Display the overview title and the used boxes (without box 0)
            IEnumerable<decimal> boxes = viewModel.Scanlist
                                                    .Where(c => c.Box > 0)
                                                    .OrderBy(c => c.Box)
                                                    .Select(c => c.Box).Distinct();
            string strboxes = "Used Boxes: ";
            for (int i = 0; i < boxes.Count(); i++)
            {
                if (boxes.ElementAt(i) > 0)
                {
                    strboxes += (boxes.ElementAt(i)).ToString("N0");
                    if (i < boxes.Count() - 1)
                        strboxes += ", ";
                }
            }
            txtUsedBoxes.Text = strboxes;
            #endregion

            #region 3. Insert the overview of the scanned articles per box
            foreach (decimal box in boxes)
            {
                await Task.Run(async () =>
                {
                    try
                    {
                        Device.BeginInvokeOnMainThread(() => AddGridBox(box));
                    }
                    catch (Exception exp)
                    {
                        await DisplayAlert("Error", exp.Message, "OK");
                    }
                });
            }
            #endregion

            #region 4. Insert the overview of the unscanned articles in box 0
            await Task.Run(async () =>
            {
                try
                {
                    Device.BeginInvokeOnMainThread(() => AddGrid0());
                }
                catch (Exception exp)
                {
                    await DisplayAlert("Error", exp.Message, "OK");
                }
            });

            Loader.IsVisible       = false;
            message1.IsVisible     = false;
            ailoader.IsRunning     = false;           
            #endregion
            
            txtUsedBoxes.IsVisible = true;
            bvLine.IsVisible       = true;
            Overview.IsVisible     = true;
        }

private async void RemoveOverview()
        {
            Loader.IsVisible       = true;
            message2.IsVisible     = true;
            ailoader.IsRunning     = true;
            Overview.IsVisible     = false;
            txtUsedBoxes.Text      = "";
            txtUsedBoxes.IsVisible = false;
            bvLine.IsVisible       = false;

            

            await Task.Run(async () =>
            {
                try
                {
                    Device.BeginInvokeOnMainThread(() => {                       
                        Overview.Children.Clear();                                                                    
                    });
                }
                catch (Exception exp)
                {
                    await DisplayAlert("Error", exp.Message, "OK");
                }
            });

            message2.IsVisible = false;            
            ailoader.IsRunning = false;
            Loader.IsVisible   = false;
        }
4urapxun

4urapxun1#

我怀疑Xamarin不会立即开始显示更新,因为它试图优化同时进行多个UI更改的情况;为了保存时间,它更喜欢用所有这些改变一起进行显示更新。
可以强制布局循环:

Device.BeginInvokeOnMainThread(() => 
{
    AddGrid0();
    // Overview is the x:Name of layout to which children are being added.
    Overview.ForceLayout();
});

警告:如果您一次显示一个框,则所用的总时间可能会增加。请考虑大约每隔三个框强制显示一次。

相关问题