【问题标题】:Xamarin forms tabbed page not retrieving data from in OnAppearingXamarin 表单选项卡式页面未从 OnAppearing 中检索数据
【发布时间】:2019-01-29 22:20:07
【问题描述】:

我从 Azure 数据库中检索数据以显示其中一个选项卡式页面。在 OnAppearing 中从 ViewModel 调用方法时不会检索数据,但当单击按钮时它会检索并显示在页面上。

请建议我是否正确构建了 ViewModel 并查看?如果是这样,为什么它不起作用。 ?

连接管理器:

    public partial class DatabaseManager
    {
    static DatabaseManager defaultInstance = new DatabaseManager();
    MobileServiceClient client;
    IMobileServiceTable<Person> personTable;

    private DatabaseManager()
    {
        this.client = new MobileServiceClient(Constants.AzureMobileAppURL);

        this.personTable = client.GetTable<Person>();
    }

    public static DatabaseManager DefaultManager
    {
        get
        {
            return defaultInstance;
        }
        private set
        {
            defaultInstance = value;
        }
    }

    public MobileServiceClient CurrentClient
    {
        get { return client; }
    }
  }

型号:

   public class Person
   {
     [JsonProperty(PropertyName = "FirstName")]
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    [JsonProperty(PropertyName = "DisplayName")]
    public string DisplayName
    {
        get { return displayName; }
        set { displayName = value; }
    }

    [JsonProperty(PropertyName = "LastName")]
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
   }

视图模型:

     public class ProfilePageViewModel : ViewModelBase
     {
    DatabaseManager manager;
    string firstName = "";
    string lastName = "";
    string displayName = "";;
    IMobileServiceTable<Person> personTable;

     public ProfilePageViewModel()
     {
       manager = DatabaseManager.DefaultManager;
        this.personTable = manager.CurrentClient.GetTable<Person>();

        RefreshCommand = new Command(
            execute: async () =>
            {
                try
                {
                    await GetProfileAsync();
                }
                catch
                {

                }

            });
          }

      public async Task GetProfileAsync()
       {
        try
        {

            IEnumerable<Person> items = await personTable
               .Where(pserson => pserson.Active)
               .ToEnumerableAsync();

            foreach (var item in items)
            {
                FirstName = item.FirstName;
                LastName = item.LastName;
                DisplayName = item.DisplayName;

            }

        }
        catch (Exception e)
        {

        }
       }

    public string FirstName
    {
        private set { SetProperty(ref firstName, value); }
        get { return firstName; }
    }

    public string LastName
    {
        private set { SetProperty(ref lastName, value); }
        get { return lastName; }
    }

    public string DisplayName
    {
        private set { SetProperty(ref displayName, value); }
        get { return displayName; }
    }

   public ICommand RefreshCommand { private set; get; }
 }

查看:

  ProfilePage.xaml
 <?xml version="1.0" encoding="utf-8" ?>
 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="SLSNZ.Views.ProfilePage"
         xmlns:controls="clr- 
             namespace:ImageCircle.Forms.Plugin.Abstractions;
             assembly=ImageCircle.Forms.Plugin"
             xmlns:local="clr-namespace:SLSNZ.ViewModels"
             Title="Profile">

  <ContentPage.Resources>
    <ResourceDictionary>
        <local:ProfilePageViewModel x:Key="viewModel">

        </local:ProfilePageViewModel>
    </ResourceDictionary>
  </ContentPage.Resources>

<ContentPage.Icon>
    <OnPlatform x:TypeArguments="FileImageSource">
        <On Platform="iOS" Value="icon-profile.png" />
    </OnPlatform>
</ContentPage.Icon>

<ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness"                     
                iOS="0, 20, 0, 0" />
</ContentPage.Padding>

    <StackLayout BindingContext="{StaticResource viewModel}">
    <Label Text="Display Name"
               TextColor="Gray"
               FontSize="Small"                
               HorizontalOptions="Start" /> 

    <Label Text="{Binding DisplayName}" 
                VerticalOptions="Center"
               HorizontalOptions="Start"                
               VerticalOptions="Start/>

     <Label Text="First Name"
               TextColor="Gray"
               FontSize="Small"                
               HorizontalOptions="Start" />

     <Label Text="{Binding FirstName}"              
               FontSize="Large" 
               HorizontalOptions="Start"                
               VerticalOptions="Start" />

     <Label Text="Last Name"  
               TextColor="Gray"
               FontSize="Small"                
               HorizontalOptions="Start" />

     <Label Text="{Binding LastName}"              
               FontSize="Large"                
               HorizontalOptions="Start"                
               VerticalOptions="Start" /> 

     <Button Text="Refresh"
                        Command="{Binding RefreshCommand}"
                        Grid.Row="0" Grid.Column="1"/>

    </StackLayout>
    </ContentPage>

查看:

  ProfilePage.cs

  public partial class ProfilePage : ContentPage
   {
  ProfilePageViewModel viewModel;

  public ProfilePage()
    {
        InitializeComponent();
        viewModel = new ProfilePageViewModel();

    }

   protected override async void OnAppearing()
    {

        base.OnAppearing();
        await viewModel.GetProfileAsync();
    }
  }

ViewModelBase:

 public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value,
                                  [CallerMemberName] string propertyName = 
    null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName 
     = null)
    {
        PropertyChanged?.Invoke(this, new 
        PropertyChangedEventArgs(propertyName));
    }
}

【问题讨论】:

  • 您找到解决问题的方法了吗
  • @G.hakim,是的,loan.burger 解决了这个问题。他在github.com/loanburger/54430503给了我一个很好的例子。

标签: xamarin.forms


【解决方案1】:

在您等待 viewModel.GetProfileAsync(); 时在您的视图中视图将已经呈现。

您在视图模型中的 GetProfileAsync 执行等待,因此将获取数据然后更新它。

我建议将 IMobileServiceTable personTable 更改为属性并实现 on Property 更改以通知视图数据发生更改。

所以你的视图模型应该实现 INotifyPropertyChanged

 public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

然后,当数据发生变化时,您可以在视图模型中通知它:

OnPropertyChanged("personTable");

在您看来,将您的代码更改为:

预初始化视图模型:

public ProfilePage()
    {
        InitializeComponent();

         SetViewModel();

    }

   protected async void SetViewModel()
    {  
       viewmodel = await viewModel.GetProfileAsync();
    }

这样您就不会阻塞 UI 线程,当您调用 OnPropertyChnage 时,它​​会通知您的视图进行更新。

更新:

我为您创建了一个小型示例 Xamarin 项目,以演示如何绑定并通知视图更改。

您的视图中也存在一些问题,其中您的 DisplayName 标签未正确关闭,并且某些标签中的 Horizo​​ntalOptions 属性重复。

下载此 Xamarin 示例。它包含硬编码数据,但会向您展示设置数据的流程和视图的绑定上下文,而无需锁定 UI 线程。

https://github.com/loanburger/54430503

【讨论】:

  • 感谢您的回答..viewModel 已经实现了类似的 OnPropertyChanged,公共类 ProfilePageViewModel : ViewModelBase
  • 所以。 ViewModelBase 有这个实现
  • ViewModelBase 有这个 INotifyPropertyChanged,请告知任何错误的实现
  • 我在视图构造函数中预初始化了 viewModel,页面加载时仍然没有出现数据。这部分 OnPropertyChanged("personTable");仍然需要完成。建议我。谢谢
  • @loan.burger 非常感谢您的帮助 :) 。根据您的示例,修改它可以工作。解决了我的问题。感谢您的出色帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 2017-03-04
  • 2020-03-31
  • 1970-01-01
  • 2018-02-25
  • 1970-01-01
相关资源
最近更新 更多