如何在首次初始化屏幕后运行代码

本文关键字:屏幕 运行 代码 初始化 | 更新日期: 2023-09-27 18:37:27

应用程序使用Caliburn.Micro及其屏幕向用户显示选项卡。

我知道IScreen.OnInitialize()方法在屏幕可见之前被调用。我想要一个代码触发屏幕对用户完全可见 - 代表屏幕的选项卡应该在那里,但不一定需要选择。

我想在屏幕完全初始化和可见后触发数据加载(并且大多数代码都在 UI 线程上本机运行,无需封送)。

这就是现在的样子。

public class MyViewModel : 
    Conductor<IScreen>.Collection.OneActive,
    IHandleWithTask<DatabaseItemChangedMessage>
{
    // This method is called by EventAggregator
    public async Task Handle(DatabaseItemChangedMessage message)
    {
        await this.LoadData(true);
    }
    protected override void OnInitialize()
    {
        base.OnInitialize();
        Task.Factory.StartNew(() => this.LoadData(false).Wait()).ContinueWith(
            task =>
                {
                    if (task.Exception != null)
                    {
                        Execute.OnUIThread(
                            () =>
                            {
                                App.HandleException(task.Exception);
                                this.TryClose();
                            });
                    }
                });
    }
    protected async Task LoadData()
    {
        try
        {
            this.WorkStarted("Loading data...");
            TLoadedData loadedData;
            ISession transaction = null;
            // using (var transaction = this.DataItemRepository.BeginTransaction())
            // {
                 loadedData = await this.LoadDataInternal(transaction);
            //     transaction.Commit();
            // }
            Execute.OnUIThread(() => this.SetLoadedData(loadedData));
        }
        finally
        {
            this.WorkFinished();
        }
    }
    protected virtual void SetLoadedData(TLoadedData loadedData)
    {
        // Updates CollectionView's source using loadedData
    }
    protected virtual async Task<TLoadedData> LoadDataInternal(ISession session)
    {
        // loads data from database and returns them
    }
    protected virtual void WorkStarted(string description)
    {
        // Sets properties using to display progress
    }
    protected virtual void WorkFinished()
    {
        // Unsets properties using to display progress
    }
}
// Just an empty class for EventAggregator purposes
public class DatabaseItemChangedMessage
{
}
// Stores data loaded from the database
public class TLoadedData
{
}

如何在首次初始化屏幕后运行代码

在我看来

,您的代码的主要问题是您正在创建一个全新的Task以执行现有的异步操作。事实上,您应该做的只是启动该操作,等待它,并根据需要处理任何异常。

例如:

public class MyViewModel : 
    Conductor<IScreen>.Collection.OneActive,
    IHandleWithTask<DatabaseItemChangedMessage>
{
    // Ideally, async methods return a Task, but here you have to
    // match the base method signature, so you're stuck with void
    protected override async void OnInitialize()
    {
        base.OnInitialize();
        try
        {
            await this.LoadData(false);
        }
        catch (Exception e)
        {
            App.HandleException(e);
            this.TryClose();
        }    
    }
    // I added the "flag" parameter, so that it matched the calls from
    // your other code
    protected async Task LoadData(bool flag)
    {
        try
        {
            this.WorkStarted("Loading data...");
            TLoadedData loadedData;
            ISession transaction = null;
            // using (var transaction = this.DataItemRepository.BeginTransaction())
            // {
                 loadedData = await this.LoadDataInternal(transaction);
            //     transaction.Commit();
            // }
            // NOTE: by changing the caller of this method so that it's
            // initiated on the UI thread, now the continuations also run
            // on the UI thread, and you don't need to explicitly invoke them there.
            this.SetLoadedData(loadedData);
        }
        finally
        {
            this.WorkFinished();
        }
    }
}