【问题标题】:OnNavigatedTo or Initialize too late for bindingOnNavigatedTo 或 Initialize 太迟无法绑定
【发布时间】:2020-02-15 12:13:48
【问题描述】:

我是使用 Xamarin.Forms 的 Prism 新手。我已经使用 Navigation 和 Commanding 类实现了 ViewModel 方法。它工作得很好,但只有一件事我不明白。将 AutowireViewModel 设置为 true 后,ViewModelLocator 会自动为我填充 BindingContext,这很不错。事情的顺序不是我所期望的。首先是 View 上属性的绑定,然后 OnNavigatedTo 被触发。这意味着当我收到视图上的参数时,我的属性初始化已经完成。我可以通过执行 RaisePropertyChanged 来解决这个问题。这会导致以下情况:

  1. 我不得不为 ViewModel 上的每个属性编写 RaisePropertyChanged,我想在视图中使用新数据查看。
  2. 所有绑定都会触发两次。对于快速的东西,这不是问题,但有些速度较慢。
  3. 视图可见后刷新数据。不会令人不安,但一次显示完成的视图及其数据会更好。
  4. 所有属性都必须能够处理空引用。

有没有办法在绑定开始之前初始化 ViewModel 中的数据?

【问题讨论】:

  • 不使用视图模型定位器? prism 团队希望您使用导航界面,遗憾的是,他们不会提供导航到已初始化视图模型的方法。
  • 在这种情况下,NavigationParameters 不合适。它会导致过多的额外代码,从而导致预期更少的复杂性。经验教训。
  • @Haukinger 请停止传播错误信息
  • @DanSiegel 需要复习吗? github.com/PrismLibrary/Prism/issues/367#issuecomment-165815286We do not recommend passing parameters via the ctor. [...] We will not be adding this to the Prism code base.
  • @Haukinger 你正在挖掘一个 5 年前的问题在这里并没有改变任何东西。 Prism 不会先做 ViewModel 导航。抱怨这一点而忽略了是否可以在将页面推送到导航堆栈之前初始化 ViewModel 从而避免昂贵的绑定更新的问题,这对人们来说是非常误导的。

标签: xamarin.forms prism


【解决方案1】:

实际上,用于 Xamarin.Forms 的 Prism 长期以来一直支持在将视图推送到 NavigationStack 之前初始化您的 ViewModel。也就是说,必须考虑操作顺序。例如,我们不能在 ViewModel 上执行一堆操作,然后将其附加到 View。

事情的执行顺序如下:

  • 视图已创建(视图 ctor 中的任何内容都已执行)
  • 如果您专门附加了 ViewModelLocator.AutowireViewModel 属性,这会将 ViewModel 解析为 ctor 的一部分
  • 如果您没有明确选择退出 ViewModelLocator 的 Autowire,导航服务将为您设置它(在 ctor 完成后)
  • NavigationService 然后将调用 IAutoInitialize/IInitialize/InitializeAsync(对于 Prism 7.2+... INavigatingAware.OnNavigatingTo 在旧版本的 Prism 中)
  • NavigationService 随后会将页面推送到导航堆栈(请注意,这可能对用户可见也可能不可见,因为在进行深度链接时可能必须先添加其他页面)
  • NavigationService 然后将调用 OnNavigatedFrom / OnNavigatedTo(人们经常报告看到由于绑定更新而出现明显的延迟。

对于绝大多数场景,如果您正确初始化了 ViewModel,则此过程完全按照您的需要进行。如果您有一些极端情况,您必须确保在设置 ViewModel 之前对其进行初始化,那么您将需要手动处理。

public partial class ViewA : ContentPage, IInitialize
{
    private ViewAViewModel ViewModel { get; }

    public ViewA(ViewAViewModel viewModel)
    {
        ViewModel = viewModel;

        // Explicitly Opt Out of Autowiring
        ViewModelLocator.SetAutowireViewModel(this, false);

        InitializeComponent();
    }

    public void Initialize(INavigationParameters parameters)
    {
        ViewModel.Initialize(parameters);
        BindingContext = ViewModel;
    }
}

【讨论】:

  • 切换到 MvvmCross,它的工作方式更加直观,代码体积也更少。
猜你喜欢
  • 2011-02-03
  • 1970-01-01
  • 1970-01-01
  • 2012-12-11
  • 2019-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-27
相关资源
最近更新 更多