使用视图模型并在 ContentView 中调用 OnAppearing

Using a view model and calling OnAppearing in ContentView

我在我的 Xamarin Forms 5 应用程序中为我的 ContentPage 使用视图模型,并且通常从代码中的 OnAppearing() 方法调用我的视图模型中的 Init() 方法落后。

我在 ContentView 中尝试了相同的方法,但它从未达到 OnAppearing() 方法。

这是我的 ContentView 代码:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MyApp.ViewModels"
             x:Class="MyApp.MyContentView">
    <ContentView.BindingContext>
        <vm:MyViewModel/>
    </ContentView.BindingContext>
    <ContentView.Content>
        <StackLayout
            BackgroundColor="{StaticResource PrimaryDark }"
            HeightRequest="200">
            <Label
                Text="{Binding User.FullName}"
                TextColor="White"
                FontSize="Medium"
                FontAttributes="Bold"
                HorizontalOptions="CenterAndExpand"/>
        </StackLayout>
    </ContentView.Content>
</ContentView>

此内容视图的视图模型如下所示:

public class MyViewModel : BaseViewModel
{
    User user;
    public MyViewModel()
    {
    }

    public User User
    {
        get => user;
        set
        {
            if (user == value)
                return;

            user = value;
            OnPropertyChanged();
         }
    }

    public async void Init()
    {
        // Get user info
        var data = await _dbService.GetUser();
        if(data != null)
        {
            User = data;
            OnPropertyChanged(nameof(User));
        }
    }
}

在我后面的代码中,这就是我正在做的:

public partial class MyContentView : ContentView
{
    MyViewModel _vm;
    public MyContentView()
    {
        InitializeComponent();
        _vm = new MyViewModel();
        BindingContext = _vm;
    }

    protected virtual void OnAppearing()
    {
        _vm.Init();
    }
}

此模式在我的内容页面中运行良好,但在内容视图中不起作用。我在这里做错了什么?

内容视图没有内容页面那样的生命周期方法。所以当content view显示或显示在屏幕上时,开发者自定义的OnAppearing()和OnDisAppearing方法将不会被调用。

因此,如果您的页面中只有一个内容视图,您可以调用页面的 OnAppearing() 方法来执行此操作。而如果contentview不是只有一个,可以在使用contentview的实例时调用 _vm.Init();方法

这是我所做的,它似乎运行良好。

首先,我创建了一个 ContentView 来显示弹出窗口 header,其中包括用户的头像和姓名。请注意,我在 XAML 文件中为此内容视图设置了视图模型——见下文:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
             xmlns:vm="clr-namespace:MyApp.ViewModels"
             x:Class="MyApp.Views.FlyoutHeader">
    <ContentView.BindingContext>
        <vm:AppViewModel/>
    </ContentView.BindingContext>
    <ContentView.Content>
        <StackLayout
            BackgroundColor="{StaticResource PrimaryDark }"
            HeightRequest="200">
            <xct:AvatarView
                Source="{Binding UserInfo.AvatarUrl}"
                Size="100"
                HorizontalOptions="CenterAndExpand"
                VerticalOptions="CenterAndExpand"/>
            <Label
                Text="{Binding UserInfo.FullName}"
                TextColor="White"
                FontSize="Medium"
                FontAttributes="Bold"
                HorizontalOptions="CenterAndExpand"
                Margin="0,0,0,30"/>
        </StackLayout>
    </ContentView.Content>
</ContentView>

然后我创建了一个名为 AppViewModel 的视图模型,我打算在多个地方使用它,包括我上面分享的 FlyoutHeader.xaml。这是 AppViewModel 的样子:

public class AppViewModel : BaseViewModel
{
   User user { get; set; }
   public AppViewModel()
   {

   }

   public User UserInfo
   {
       get => user;
       set
       {
           if (user == value)
               return;

           user = value;
           OnPropertyChanged();
       }
   }

   public async void Init()
   {
       if(user == null || user.Id == Guid.Empty)
       {
           var data = await _dbService.GetUser();
           if(data != null)
           {
               UserInfo = data;
               OnPropertyChanged();
           }
       }
   }
}

最后,在FlyoutHeader.xaml.cs的后面的代码中,我在构造函数中调用了视图模型的Init()方法:

public partial class FlyoutHeader : ContentView
{
     AppViewModel _vm;
     public FlyoutHeader()
     {
         InitializeComponent();
         _vm = new AppViewModel();
         _vm.Init();

         BindingContext = _vm;
     }
}

我实际上有点担心与 UI 的紧密耦合以及在构造函数中启动的 async 调用可能会占用 UI 线程并延迟它.如果有更好的方法来处理这个问题,请告诉我。