1

初めての Windows 8 クライアントを作成しています。非同期メソッドを使用してプロパティをロードしたのもこれが初めてなので、これが初歩的な質問である場合はご容赦ください。

私は WCF サービスを持っており、クライアント用のビジュアル スタジオの分割ページ テンプレートから開始しました (ただし、ほとんどすべてを置き換えます)。

「SplitPage」コードの背後にあるビューに直接データを取得すると、すべてが適切にロードされて表示されます。ただし、MVVM を使用しようとすると、バインドされたときにプロパティに項目がありません。WCF のため、データを取得するための非同期呼び出しが問題の原因ですか? プロパティを返す前にデータが戻っていることを確認する方法はありますか (プロパティ自体には非同期のラベルを付けることができないようです)。

これが私がしたことです:

テスト目的で、ListView を配置し (コードは listbox と表示されていますが、XAML では listview を使用しました)、OnNavigatedTo ハンドラーで呼び出される非同期メソッドとして次のコードを追加しました。

private async void GetUsersList()
{
   ServiceClient client = new ServiceClient();
   List<UserDTO> _users = (await client.GetUsersAsync()).ToList();
   foreach(UserDTO user in _users)
   {
      UserListBox.Items.Add(new UserView(user));
   }
   TestStack.Children.Add(new UsersView());
}

これは正常に機能し、ページが読み込まれると、UserListBox に UserViews が含まれます。

次に、完全な MVVM パターンに入ろうとし、UsersViewModel と UsersView (複数) を、コンストラクターで、WCF サービスから取得した UserDTO の ObservableCollection を使用してプロパティ Users を初期化するリポジトリと共に作成しました。上記のメッセージの最後の行が行っているのは、ビューをページのスタックパネルに設定することです。

ビューとビューモデルはリソース ファイルにまとめられています。

<DataTemplate x:Key="vm:UsersViewModel">
    <vw:UsersView />
</DataTemplate>

どうやら .Net 4.5 には DataTemplates の x:Type プロパティがないため、バインディングは私が慣れ親しんでいるものとは少し異なります。

データがロードされるリポジトリの部分は次のようになります。

    private ObservableCollection<UserDTO> _users = new ObservableCollection<UserDTO>();
    private ServiceClient _client = new ServiceClient();

    public UserRepository()
    {
        GetUsers();
    }

    public async void GetUsers()
    {
        var tempList = await _client.GetUsersAsync();
        foreach(UserDTO item in tempList)
        {
            _users.Add(item);
        }
    }

UsersViewModel のコンストラクターが行う唯一のことは、リポジトリのインスタンスを作成し、UserViewModel アイテムを UserViewModel の観察可能なコレクションにロードすることです。

public UsersViewModel()
{
   _repo = new UserRepository();
   foreach (UserDTO item in _repo.Users)
   {
      _users.Add(new UserViewModel(item.Id));
   }
}

出力ステートメントをどこにでも配置しようとしましたが、SplitPage コード内の同じコードが WCF のフィード元のデータベースに既にあるテスト項目を返しても、プロパティ "getter" が空のリストを返すことを確認しました。コードが実行されるスレッドと同じくらい単純なものでしょうか? おそらく、SplitPage は UI スレッドで WCF への呼び出しを実行しているため、データの非同期呼び出しが返されるまでバインドは行われませんが、何らかの理由で MVVM を使用すると、データがバックグラウンド スレッドに読み込まれている間にすぐにデータ バインドが行われますか? もしそうなら、それが ObservableCollection であるという事実は、データが最終的にプロパティに表示されたときに UI に通知されるべきではありませんか?

4

1 に答える 1

2

asyncメソッドは、実行が完了する前に戻ります。ユーザーがロードされる前にコンストラクターに返されたGetUsersコンストラクターに返されたため、ユーザーは表示されません。UserRepositoryUsersViewModel

私が最も好む解決策は、たとえばUserRepository次のような非同期ファクトリ メソッドです。

private UserRepository()
{
}

private async Task InitializeAsync()
{
    var tempList = await _client.GetUsersAsync();
    foreach(UserDTO item in tempList)
    {
        _users.Add(item);
    }
}

public static async Task<UserRepository> Create()
{
    var ret = new UserRepository();
    await ret.InitializeAsync();
    return ret;
}

ファクトリ メソッド アプローチの最大の利点は、async初期化されていないインスタンスを取得できないことです。

ただし、 IoC/DI やデータ バインディングなど、ファクトリ メソッドではなくパブリック コンストラクターが必要な特定の状況があります。async

このような場合、次のパターンが役立ちます。

public MyConstructor()
{
  Initialized = InitializeAsync();
}

public Task Initialized { get; private set; }
private async Task InitializeAsync()
{
  // asynchronous initialization here
}

次のようにリポジトリに適用できます。

private ObservableCollection<UserDTO> _users = new ObservableCollection<UserDTO>();
private ServiceClient _client = new ServiceClient();

public UserRepository()
{
    Initialized = InitializeAsync();
}

public Task Initialized { get; private set; }
private async Task InitializeAsync()
{
    var tempList = await _client.GetUsersAsync();
    foreach(UserDTO item in tempList)
    {
        _users.Add(item);
    }
}

その後、依存クラスで同じパターンを使用できます。

public UsersViewModel()
{
    _repo = new UserRepository();
    Initialized = InitializeAsync();
}

public Task Initialized { get; private set; }
private async Task InitializeAsync()
{
    // Wait for the repository to initialize
    await _repo.Initialized;

    foreach (UserDTO item in _repo.Users)
    {
        _users.Add(new UserViewModel(item.Id));
    }
}

補足として: 原則として、async void. 私のasync/awaitイントロが役に立つかもしれません。

于 2013-01-07T04:31:20.107 に答える