Xamarin表单选项卡式页面无法从OnAppearing中检索数据

时间:2019-01-29 22:20:08

标签: xamarin.forms

我从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; }
    }
   }

ViewModel:

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

1 个答案:

答案 0 :(得分:1)

在您等待viewView.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