【问题标题】:mvvmcross Viewmodel.Initialize is fired before you can hook InitializeTask.PropertyChanged在您可以挂钩 InitializeTask.PropertyChanged 之前触发 mvvmcross Viewmodel.Initialize
【发布时间】:2018-02-13 00:10:43
【问题描述】:

在我的应用程序中,我想在初始化完成时在视图中知道。问题是它会在您挂钩 InitializeTask.PropertyChanged 之前启动。这是我的 ViewModel 代码:

    public override async Task Initialize()
    {
        ClientID = await MyDataSource.GetClientID();

    }

在我看来,我正在做以下事情:

    protected override void OnViewModelSet()
    {
        var vm = this.DataContext as MyViewModel;

        vm.InitializeTask.PropertyChanged += InitializeTask_PropertyChanged;

        base.OnViewModelSet();
    }

    private void InitializeTask_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "IsSuccessfullyCompleted")
        {
            vm.InitializeTask.PropertyChanged -= InitializeTask_PropertyChanged;
            if (vm.ClientID != "")
                posClient = new PosClient(this, vm.ClientID);
        }
    }

据我所知,OnViewModelSet 是您在 View 中访问 ViewModel 的最快方法。如果我设置断点,Initialize 在 OnViewModelSet 被触发之前运行。这使得 Initialize 很可能在您挂钩事件之前已经完成。视图中是否还有其他地方可以在 Initialize 开始之前挂钩事件,从而保证 Initialize.PropertyChanged 将在视图中触发?

**** 更新****

我遵循@fmaccaroni 的建议并实现了一个名为 DataLoaded 的 MvxInteraction。我做的一件不同的事情是创建一个单独的函数来加载数据。

    public void LoadData()
    {
        Task.Run(async () =>
        {
            ClientID = await IHSDataSource.GetClientID();
            _DataLoaded.Raise();
        });
    }

在连接交互事件之前,我担心异步任务完成。这样做,我在视图中添加了这个。

    protected override void OnViewModelSet()
    {
        vm = this.DataContext as InvoiceViewModel;

        var set = this.CreateBindingSet<InvoiceView, InvoiceViewModel>();
        set.Bind(this).For(view => view.DataLoaded).To(viewModel => viewModel.DataLoaded).OneWay();
        set.Apply();

        vm.LoadData();

        base.OnViewModelSet();
    }

这样,LoadData 不会启动,直到我确定结果会触发交互并保证我得到结果。这是我第一次听说 MvxInteraction,我现在一直在使用它。

【问题讨论】:

    标签: c# android xamarin xamarin.android mvvmcross


    【解决方案1】:

    我不确定你想要实现什么,但如果你想在Initialize 结束时在你的视图中采取行动,只需执行MvxInteraction 并在你的await 之后调用它,即:

    视图模型:

    private MvxInteraction _interaction = new MvxInteraction();
    public IMvxInteraction MyMvxInteraction => _interaction;
    
    public override async Task Initialize()
    {
        ClientID = await MyDataSource.GetClientID();
        this._interaction.Raise();
    }
    

    查看:

    private IMvxInteraction _interaction;
    public IMvxInteraction MyMvxInteraction
    {
        get => this._interaction;
        set
        {
            if (this._interaction != null)
                this._interaction.Requested -= this.OnInteractionRequested;
    
            this._interaction = value;
            this._interaction.Requested += this.OnInteractionRequested;
        }
    }
    
    private void OnInteractionRequested(object sender, EventArgs e)
    {
        var vm = this.DataContext as MyViewModel;
    
        if (vm.ClientID != "")
            posClient = new PosClient(this, vm.ClientID);
    }
    

    以及视图中的绑定:

    var set = this.CreateBindingSet<MyView, MyViewModel>();
    set.Bind(this).For(view => view.MyMvxInteraction).To(viewModel => viewModel.MyMvxInteraction).OneWay();
    set.Apply();
    

    【讨论】:

    • 我应该把装订放在哪里?在 OnCreate 中?
    • 即使是这种方法,您也需要在 Initialize 被触发之前将其连接起来。也许将绑定放在视图的构造函数中?
    • 在活动中,在 OnCreate 和 Fragment OnCreateView 中
    • 可以放在base.OnCreate之前吗?似乎它不会及时连接,因为(我认为) base.OnCreate 是 Initialize 被触发的地方。
    猜你喜欢
    • 1970-01-01
    • 2015-09-01
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 2022-12-15
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    相关资源
    最近更新 更多