C# 在Windows Universal 8.1上使用异步方法

C# 在Windows Universal 8.1上使用异步方法,c#,windows-phone-8.1,windows-8.1,C#,Windows Phone 8.1,Windows 8.1,我有一个页面(主页)和SQLite数据库。我需要先读取SQLite数据库,然后更新我的页面控件。 这是我的页面代码: public MainPage() { this.InitializeComponent(); // Get SQLite and language setting SQLiteData(); // Update controls in page GetConnec

我有一个页面(主页)和SQLite数据库。我需要先读取SQLite数据库,然后更新我的页面控件。
这是我的页面代码:

public MainPage()
    {           
        this.InitializeComponent();

        // Get SQLite and language setting
        SQLiteData(); 

        // Update controls in page
        GetConnectionList(); 
    }
这是SQLiteData()的代码:

public异步void SQLiteData()
{
conn=新的SQLiteAsyncConnection(“Setting.db”);
等待连接CreateTableAsync();
等待连接CreateTableAsync();
....
}
因为我在SQLiteData()中使用了“wait”,所以调试器在未完成的情况下运行GetConnectionList(),并从SQLite获取数据,所以我的应用程序中出现错误。
我怎样才能解决这个问题?能帮我吗?

谢谢。

一种方法是将异步初始化从OnNavigatedTo中的ctor中移出。但是,您必须意识到OnNavigatedTo将在其异步部分完成之前将控件返回到框架。这可能是好的,但是你需要考虑如何处理错误。 不过,我会以稍微不同的方式构造此代码:

...

// The UI will use data binding to PageState to show 
// UI specific for the initialization phase.
public PageState PageState {get; private set {.../*include property change notification */...};}

// The UI will use data binding to ErrorMessage as needed.
public string ErrorMessage {get; private set {.../*include property change notification */...};}

...

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    await InitializeAsync();
}

private async Task InitializeAsync()
{
    try
    {
        // Have the UI bind to 
        PageState = PageState.InitializingInProgress;

        await SQLiteData(); 

        GetConnectionList();

        ...

        PageState = PageState.InitializedOk;
    }
    catch(...)
    {
        PageState = PageState.InitializedWithError;
        ErrorMessage = ...
    }
}

}

关键在于您将SQLiteData声明为异步,但在主页面构造函数中,您没有“等待”SQLiteData任务完成

您应该等待SQLiteData完成,但在构造函数内部无法轻松完成此操作。。。你也不应该。

请将耗时的异步任务移出构造函数并移入类中的其他方法中,一个关键原因是您可以实现一些更好的错误处理例程,并且在连接第一次失败时可以重新执行连接逻辑

public async InitialiseDataConnections()
{           
    // Get SQLite and language setting
    await SQLiteData(); 

    // Update controls in page
    GetConnectionList(); 
}    
现在您有了一个可以从构造函数调用的单一用途方法。。。但更好的解决方案是从page类上的OnNavigatedTo事件处理程序调用它

编程中的一个普遍期望是,与对对象执行操作相比,创建对象实例应该相对轻量级。下面是一个有趣的讨论:

在通用应用程序中,轻量级配置预计在构造函数中处理,大部分初始化“逻辑”延迟,直到页面实际导航到(OnNavigatedTo)。特别是当我们考虑数据访问方案时,数据可能是最重要的,尽可能最新的,但还有另一个重要事件,当导航到页面已经导致向后导航或应用程序已被恢复。在这些事件中,您可能能够从以前的序列化状态获取某些状态或配置,而不是重新初始化所有可能耗时的过程

因此,这里的“最佳实践”是使用OnNavigatedTo处理任何页面初始化,而不是创建页面控件。您可以访问NavigationEventArgs,它将帮助您以用户期望的状态重新创建页面。在这里,其他开发人员将首先查看页面后面的业务逻辑,并且您可以将OnNavigatedTo处理程序声明为异步

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    await InitialiseDataConnections();
}

代码对我来说很难。我读了它,但我不明白为什么会出错。当我出错时?重要吗?我指的是运行SQLite代码时可能出现的潜在错误。如果代码太难,那么从这个开始-只需将OnNavigatedTo中初始化的异步部分移动到。还要小心-第二次运行应用程序时可能会失败,因为您正在尝试创建已经存在的表。您可能需要添加更多代码,以避免在第二次运行时创建相同的表。复制此代码时在PageState上出错?我现在才使用pageState。暂时忽略try/catch、pageState和ErrorMessage。您甚至可以删除InitializeAsync,并将对它的调用替换为两行,其中我调用“await SQLiteData();”和“GetConnectionList();”。您遇到的主要问题现在已经解决,因为您现在可以在GetSqlite中使用await.I ckeck调用SQLiteData以获取重复表。我将我的主页设置为emuty,并在onnavigateto中使用我的代码。它工作得很好,但我有问题。我更改了我的应用程序语言,所以我需要在初始化之前加载GetSQLite,以检查所选的语言并进行更改。您应该认真研究设计模式。在本例中,MVVM以及服务和存储库模式。
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    await InitialiseDataConnections();
}