2

Split Page サンプル アプリに基づいて Windows 8 Metro アプリを作成しました。ただし、サンプル アプリでは、データはコンストラクターで同期的に読み込まれます。テキスト ファイルにアクセスしているため、データを非同期的にロードする必要があります。コンストラクタは次のようになります。

    public MyDataSource()
    {
        DataLoaded = false;

        LoadData();
    }

LoadData()データモデルを設定する非同期メソッドです。これは正常に機能し、データをそのまま表示します (これは私が望む動作です)。サスペンドと終了をテストしようとすると、問題が発生します。問題は、データが取り込まれる前にリカバリがデータ モデルにアクセスしようとする可能性があることです。

    public static MyDataGroup GetGroup(string uniqueId)
    {
        // If the data hasn't been loaded yet then what?
        if (_myDataSource == null)
        {
        // Where app has been suspended and terminated there is no data available yet
        }

        // Simple linear search is acceptable for small data sets
        var matches = _myDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
        if (matches.Count() == 1) return matches.First();
        return null;
    }

コンストラクターを call に変更することでこれを修正できますLoadData().Waitが、これはアプリが UI スレッドをロックすることを意味します。私が必要としているのはGetGroup、UI スレッドをロックせずにデータがロードされるまで回復コードを取得する方法です。これは可能ですか、または推奨されますか? もしそうなら、どのように?

編集:

のタスクをキャッシュすることを提案した人が 1 人か 2 人いますLoadData()。これは素晴らしいアイデアですが、内部のコードGetGroupはページ状態管理セクションによって呼び出されるため、非同期にすることはできません。これを回避するために、次のことを試しました。

if (!DataLoaded)
{
    //dataLoading = await MyDataSource.LoadData();
    dataLoading.RunSynchronously();
}

しかし、これは私にエラーを与えます:

RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.

dataLoading.Wait()

UIをロックするだけです。

4

5 に答える 5

5

これは、コンストラクターを作成した場合に最適なオプションのように聞こえると思いますasync。しかし、それは不可能なので、代わりにできることは、のasyncファクトリ メソッドを作成することMyDataSourceです。

private MyDataSource()
{
    DataLoaded = false;
}

public static async Task<MyDataSource> Create()
{
    var source = new MyDataSource();
    await source.LoadData();
    return source;
}

そして、次_myDataSourceを使用して初期化しawaitます。

_myDataSource = await MyDataSource.Create();

何らかの理由でそれができない場合はTask、ファクトリ メソッドによって返された を格納して、 で待機できGetGroup()ます。

_myDataSourceTask = MyDataSource.Create();

…

public static async Task<MyDataGroup> GetGroup(string uniqueId)
{
    var myDataSource = await _myDataSourceTask;

    // Simple linear search is acceptable for small data sets
    var matches = myDataSource.AllGroups.Where(group => group.UniqueId == uniqueId);
    if (matches.Count() == 1) return matches.First();
    return null;
}
于 2012-07-18T19:51:30.253 に答える
1

LoadDataが非同期の場合、待機可能なものをすべて保存し(または新しいものを作成し)、それを公開します(たとえば、タスクのように)。GetGroupは非同期としてマークされ、var data =await_myDataSource.LoadTaskなどを実行できます。

于 2012-07-18T19:21:54.787 に答える
1

Svick は Tasks を使用しているため、質問への回答に最も近いと思います。GetGroup メソッドでタスクを返すか、LoadAsync メソッドでタスクを返すかは、おそらく問題ではありません。重要なのは、そのタスクをキャプチャして、後で再開するときに参照することです。

Task クラスはここに文書化されており、 IsCanceled 、 IsCompletedIsFaultedなどのプロパティがあることに気付くでしょう。コンストラクターが LoadAsync メソッドを開始すると、返される Task をクラスレベルの変数として保存できます。後でレジューム コードが開始されたときに、タスクがまだ実行されているかどうか (つまり、完了しておらず、エラーが発生していないかどうか) を確認できます。タスクが完了したら、すぐに履歴書コードを実行できます。まだ完了していない場合は、Task.ContinueWithを使用して、タスクの完了時に再開コードが実行されるようにスケジュールできます。

于 2012-07-18T20:47:39.313 に答える
0

Windows 8 はまだチェックアウトしていませんが、Silverlight (または WPF) を使用してアプリを開発すると仮定すると、Windows Phone と同様に機能すると思いますが、これはあなたの質問からはわかりません。Silverlight を使用する場合:

INotifyPropertyChanged インターフェイスと ObservableCollection-s を使用して、データを UI にバインドできるようにする必要があります。そうすれば、データを変更するたびに、UI に変更が通知され、バインディングが更新されます。

于 2012-07-18T17:48:59.773 に答える
0

MyDataGroup iNotifyPropertyChanged を実装するパブリック プロパティ。

UniqueID はパブリック プロパティです。UniqueID の変更が MyDataGroup = null に設定されたら、BackGroundWorker を var mathces = に呼び出しますが、それを遅らせます。は働いている。これはバックグラウンドにあるため、遅延によって UI が拘束されることはありません。コールバックで MyDataGroup を設定すると、UI に通知が届きます。UniqueID が変更されたとき (実行中の場合) にバックグラウンドワーカーをキャンセルしたいので、backgroundworker がキャンセル可能であることを確認してください。

これは WPF で行うので、Metro に変換されない場合は申し訳ありませんが削除します。

于 2012-07-18T20:29:35.727 に答える