c# - 将数据从 WCF 绑定(bind)到 MVVM 客户端始终为空

标签 c# wcf mvvm windows-8

我正在制作我的第一个 Windows 8 客户端。这也是我第一次使用异步方法来加载属性,所以如果这是一个菜鸟问题,请原谅我。

我有一个 WCF 服务,并从 Visual Studio 中客户端的拆分页面模板开始(但我几乎要替换所有内容)。

当我将数据直接放入“SplitPage”代码中的 View 时,所有内容都已正确加载并显示出来。但是,当我尝试使用 MVVM 时,该属性在绑定(bind)时没有任何项目。由于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。这就是上述消息的最后一行所做的就是将 View 设置为页面上的堆栈面板。

View 和 View 模型在资源文件中粘合在一起:
<DataTemplate x:Key="vm:UsersViewModel">
    <vw:UsersView />
</DataTemplate>

绑定(bind)与我习惯的有点不同,因为显然 .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));
   }
}

我已经尝试将输出语句放在任何地方,并且确实“getter”属性返回了一个空列表,即使直接在 SplitPage 代码中的相同代码返回了我已经在 WCF 提供的数据库中的测试项目。它可以像代码运行的线程一样简单吗?也许 SplitPage 正在 UI 线程上运行对 WCF 的调用,因此在数据异步调用返回之前不会发生绑定(bind),但是由于某种原因使用 MVVM 时,数据绑定(bind)会在后台线程上加载数据时立即发生?如果是这样,当数据最终确实出现在属性中时,它是 ObservableCollection 的事实不应该通知 UI 吗?

最佳答案

async方法在完成执行之前返回。您没有看到任何用户,因为 GetUsers返回UserRepository返回 UsersViewModel 的构造函数加载用户之前的构造函数。

我最喜欢的解决方案是异步工厂方法,例如 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的最大好处工厂方法方法是您永远不会获得尚未初始化的实例。

但是,在某些情况下,您必须使用公共(public)构造函数而不是 async。工厂方法,例如 IoC/DI 或数据绑定(bind)。

在这种情况下,我发现以下模式很有帮助:
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 intro有帮助。

关于c# - 将数据从 WCF 绑定(bind)到 MVVM 客户端始终为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14183258/

相关文章:

c# - 需要额外括号的 boolean 语句

c# - 如何在客户端连接时通知 WCF 服务的主机?

c# - 将数据表发送到 WCF 服务时出现序列化错误

c# - 每个 View 模型的 Autofac 实例

c# - MVVM: View 导航无法正常工作

wpf - 带有Ninject的MVVM ViewModelLocator

c# - 从生成的表中检索数据时对象名称 'dbo.TableName' 无效

c# - 创建 MS Word 文档时如何插入分页符

C# 十进制格式化查询

c# - 在 WCF 服务中序列化 SOAP xml 节点时出现问题