首页 > 解决方案 > 无法在第一页加载时从选择器加载数据,但在第二次访问页面时选择器按预期加载

问题描述


我有一个显示产品列表的 xamarin 页面和一个代表产品类型的选择器。我的问题是,当我启动应用程序并第一次尝试访问页面时,
在调试模式下,我可以看到我正在使用的列表,因为 ItemsSource 具有价值,
但是当页面加载时,选择器显示为灰色并且没有任何数据。
当我用选择器离开页面并第二次打开它时,选择器已加载数据!
这是我的代码!
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         
         xmlns:Converters="clr-namespace:eProdaja.Mobile.Converters"
         mc:Ignorable="d"
         x:Class="Restoran.Mobile.Views.ProizvodiPage">

<ContentPage.Resources>
    <ResourceDictionary>
        <Converters:ImageConverter x:Key="imgConv"></Converters:ImageConverter>
    </ResourceDictionary>
    
</ContentPage.Resources>
<ContentPage.Content>
    <StackLayout>
        <Picker ItemsSource="{Binding TipProizvodaList}"  ItemDisplayBinding="{Binding Naziv}" SelectedItem="{Binding SelectedTipProizvoda}"></Picker>
        <ListView ItemsSource="{Binding ProizvodiList}" ItemSelected="ListView_ItemSelected" >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout  Padding="10" Margin="5" HorizontalOptions="CenterAndExpand" >
                            <Image Source="{Binding Slika, Converter={StaticResource imgConv}}" ></Image>
                            <Label Text="{Binding Naziv}" 
                            d:Text="{Binding .}"
                            LineBreakMode="NoWrap" 
                            Style="{DynamicResource ListItemTextStyle}" 
                            FontSize="16" HorizontalTextAlignment="Center" HorizontalOptions="CenterAndExpand" />
                            <Button  HorizontalOptions="Center" BorderColor="Transparent" BackgroundColor="Transparent" TextColor="OrangeRed" Text="Dodaj u košaricu"></Button>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>



        </ListView>
    </StackLayout>
</ContentPage.Content>

xaml.cs 中的代码
private ProizvodiViewModel model = null;
        public ProizvodiPage()
        {
            InitializeComponent();
            BindingContext = model = new ProizvodiViewModel();
        }

    protected async override void OnAppearing()
    {
        base.OnAppearing();
        await model.Init();
    }

viewModel 内的代码
public ObservableCollection<TipProizvoda> TipProizvodaList { get; set; } = new ObservableCollection<TipProizvoda>();

 public async Task Init()
    {

         if (TipProizvodaList.Count == 0)
        {
            var TPList = await _tipProizvoda.Get<List<TipProizvoda>>(null);
            TipProizvodaList.Clear();
            TipProizvoda empty = new TipProizvoda { TipProizvodaID = 0, Naziv = "" };
            TipProizvodaList.Add(empty);

            foreach (var tipProizvoda in TPList)
            {
                TipProizvodaList.Add(tipProizvoda);
            }
        }
    }

标签: c#xamarinxamarin.formsuwp-xaml

解决方案


多年来,我在尝试做任何OnAppearing影响屏幕上所见内容的事情时遇到了各种问题。

Xamarin 必须在 OnAppearing 之后执行某些操作,以使页面进入有效状态以接收绑定更改。

解决此限制的一种方法是延迟您想要完成的工作,以便在您的工作设置绑定之前OnAppearing返回。

这样做的“缺点”是页面将在没有您的工作的情况下出现(起初) 。请参阅对“activityIndi​​cator”的两个引用 - 在您的工作准备好之前,您可以控制希望用户看到的内容。

这样做的“好处”是它确保 Xamarin“看到”您的绑定更改。(如果需要,它还提供了一个进行慢速后台工作的地方。)

尝试这个:

public partial class MyPage : ...
{
    protected override void OnAppearing()
    {
        base.OnAppearing();

        This returns immediately, allowing OnAppearing to return.
        DelayWork(100, BackgroundWork, UIWork);
    }
    
    // Custom class, used to pass results from background work to UI work.
    class BackgroundResult {
        ...
    }
    
    private void DelayWork(int milliseconds, Func<BackgroundResult> backgroundWork, Action uiWork)
    {
        //OPTIONAL activityIndicator.IsRunning = true;

        Task.Run( () => {
            // The delay ensures Xamarin page preparation has a little time, before your work begins.
            // Without this delay, under some circumstances, the page might not show up as quickly.
            // You might not need this.
            Task.Delay(milliseconds);
            
            // Slow work -- do nothing that affects UI.
            BackgroundResult backgroundResult = BackgroundWork();
            
            Device.BeginInvokeOnMainThread(async () => {
                await uiWork(backgroundResult);
            });
        });
    }

    private BackgroundResult BackgroundWork()
    {
        // Slow work -- do nothing that affects UI.
        ...
        
        // fill this with whatever info you need to pass to UIWork.
        var backgroundResult = new BackgroundResult();
        // ...
        return backgroundResult;
    }

    private async void UIWork(BackgroundResult backgroundResult)
    {
        // Work that affects UI, possibly via Bindings.
        await model.Init();

        //OPTIONAL activityIndicator.IsRunning = false;
    }
}

在您的情况下,您可能不需要 BackgroundWork 或 BackgroundResult。显示完整性。


推荐阅读