从绑定WCF数据到客户端的MVVM总是空 [英] Binding data from WCF into a MVVM client always empty

查看:123
本文介绍了从绑定WCF数据到客户端的MVVM总是空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm making my first Windows 8 client. This is also the first time I've used async methods to load a property so please forgive me if this is a noobie question.

我有一个WCF服务,并从开始在Visual Studio中拆分页面模板客户端(但我要非常取代一切)。

I have a WCF service and started from the Split Page template in visual studio for the client (but I'm going to pretty much replace everything).

当我直接拿到的内部数据到我的意见一切的背后SplitPage代码是正确加载和显示出来。然而,当我尝试使用MVVM的属性不会有任何项目时,它得到约束。因为WCF的是一个异步调用得到的数据是,这个问题的原因是什么?有没有去确保他们的数据返还财产前回(属性似乎自己不能够被标记异步)?

When I get the data into my Views directly inside of the "SplitPage" code behind everything is loaded properly and shows up. However, when I try to use MVVM the property doesn't have any items in it when it gets bound. Because of WCF it is an async call to get the data is that the cause of the problem? Is there away to make sure that they data is back before returning the property (properties themselves don't seem to be able to be labelled async)?

下面是我做了什么

有关测试的目的,我把一个ListView(代码表示,列表框,但我在XAML列表视图去),并添加以下代码中调用的OnNavigatedTo处理异步方法

For testing purposes I put a ListView (code says listbox but I went with listview in the XAML) and added the following code as an async method called in the OnNavigatedTo handler:

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。

This works fine and when the page loads the UserListBox contains the UserViews.

我又试图进入一个完整的MVVM模式和一个仓库,在其构造函数初始化属性用户UserDTOs的一个ObservableCollection一起做了一个UsersViewModel和UsersView(复数),它从我的WCF服务拉动。这就是上述消息的最后一行正在做的是设置视图到页面上的StackPanel。

I then tried to go into a full MVVM pattern and made a UsersViewModel and UsersView (plural) along with a repository that in its constructor initializes a property Users with an ObservableCollection of UserDTOs it has pulled from my WCF service. That is what the last line of the above message is doing is setting the view into a stackpanel on the page.

视图和视图模型是粘在一起的资源文件

The view and the viewmodel are glued together in a resources file:

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



绑定是有点不同的,比我已经习惯了,因为显然.NET 4.5没有在X:上的DataTemplates了类型属性

The binding is a little different than I'm used to since apparently .Net 4.5 doesn't have the x:Type property on DataTemplates anymore.

在数据被加载的外观如下库的一部分:

The part of the repository where the data is loaded looks as follows:

    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的的ObservableCollection:

The only thing that the constructor for the UsersViewModel does is create an instance of the repository and load UserViewModel items into its observablecollection of UserViewModel:

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



我试图把输出语句随处可见,果然属性吸气将返回一个空列表,即使直接在相同的代码中SplitPage代码返回已经在数据库WCF从喂养我的测试项目。难道作为代码运行的线程一样简单的东西吗?也许SplitPage运行在UI线程中调用WCF这样的结合不会发生,直到数据异步调用返回但MVVM由于某些原因发生的数据绑定马上当数据被加载在后台线程?如果是的话应该不是事实,这是一个ObservableCollection得到当数据最终会出现在物业通知的UI?

I've tried putting output statements everywhere and sure enough the properties "getter" is returning an empty list even though the same code directly in the SplitPage code returns my testing items that are already in the database WCF is feeding from. Could it be something as simple as the thread that the code runs on? Perhaps SplitPage is running the call to WCF on the UI thread so the binding doesn't happen until the data async call has returned but with MVVM for some reason the databinding happens right away while the data is loaded on a background thread? If so shouldn't the fact that it is an ObservableCollection get the UI notified when the data finally does appear in the property?

推荐答案

异步方法返回他们已经执行完毕之前。你没有看到任何用户,因为 GetUsers 返回到返回 UserRepository 构造 UsersViewModel 构造被装在用户面前。

async methods return before they have finished executing. You're not seeing any users because GetUsers returned to the UserRepository constructor which returned to the UsersViewModel constructor before the users were loaded.

该解决方案,我最喜欢是异步的工厂方法,例如,为 UserRepository

The solution I most prefer is asynchronous factory methods, e.g., for 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;
}



的异步最大的好处工厂方法的方法是不会让你尚未初始化一个实例。

The biggest benefit of the async factory method approach is that you never get an instance that hasn't been initialized.

不过,也有在那里你的必须有一个公共的构造函数,而不是一个异步工厂方法,如IOC / DI或数据绑定。

However, there are certain situations where you must have a public constructor rather than an async factory method, e.g., IoC/DI or data binding.

在这样的情况下,我找到下面的模式有帮助的:

In cases like these, I find the following pattern helpful:

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

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

您可以把它应用到你的资料库是这样的:

You could apply it to your repository like this:

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);
    }
}

您就可以使用同样的模式在你的依赖类

You can then use the same pattern in your dependent class:

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));
    }
}



作为一个方面说明:您应该一般规则避免异步无效。您可能会发现我的 异步 / 的await 介绍有帮助的。

As a side note: as a general rule you should avoid async void. You may find my async/await intro helpful.

这篇关于从绑定WCF数据到客户端的MVVM总是空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆