【问题标题】:Wpf MVVM - Binding not applied in ViewModel before View is showing (Async / await)Wpf MVVM - 在 View 显示之前未在 ViewModel 中应用绑定(异步/等待)
【发布时间】:2016-04-24 18:25:41
【问题描述】:

当我尝试在 ViewModel 中绑定 ObservableCollection 时,我遇到了一个小错误。问题是它连接到一个 web api 来获取列表,但由于某种原因,它不够快。

我认为它与 async / await 有关,它不会在加载视图之前等待列表获取其数据。

代码:

public ObservableCollection<AvailableRoomModel> AvailableRooms { get; set; }
public ObservableCollection<AvailableRoomModel> List { get; set; }

AvailableRooms 是正确的列表,该列表仅用于测试。

public RoomsViewModel(IGetAvailableRoomsService getAvailableRoomsService)
{
    //Injection
    _getAvailableRoomsService = getAvailableRoomsService;

    //Initialize
    AvailableRooms = new ObservableCollection<AvailableRoomModel>();

    //Get all rooms
    GetAvailableRooms();

    List = new ObservableCollection<AvailableRoomModel>();

    List.Add(new AvailableRoomModel { Id = 1, RoomNumber = "101", Occupied = true });
    List.Add(new AvailableRoomModel { Id = 2, RoomNumber = "102", Occupied = true });
    List.Add(new AvailableRoomModel { Id = 3, RoomNumber = "103", Occupied = true });
}


public async void GetAvailableRooms()
{
    try
    {
        AvailableRooms = await _getAvailableRoomsService.getRooms();
    }
    catch (Exception e)
    {
        //TODO   
    }

}

已经测试过,如果我将我的 ItemsControl 绑定到 name = List 的列表,它可以工作(它足够快),但在绑定到 AvailableRooms 时它不起作用。

我真的不希望在我可以点击的视图中有一个 searchCommand,只想在显示视图之前填充列表。

有什么想法吗?

【问题讨论】:

    标签: c# wpf asynchronous mvvm


    【解决方案1】:

    问题是async void。如果你想等待一个方法,那么它的返回类型必须是Task 或Task&lt;T&gt;。

    public async Task<IEnumerable<AvailableRoomModel>> GetAvailableRooms()
    {
        try
        {
            return await _getAvailableRoomsService.getRooms();
        }
        catch (Exception e)
        {
            //TODO   
        }
    }
    

    在ctor中你不能等待这个方法,所以你可以像这样简单地调用这个方法:

    public RoomsViewModel(IGetAvailableRoomsService getAvailableRoomsService)
    {
        //Injection
        _getAvailableRoomsService = getAvailableRoomsService;
    
        //Get all rooms
        AvailableRooms =
            new ObservableCollection<AvailableRoomModel>(
                GetAvailableRooms().GetAwaiter().GetResult()
            );
    
        // ...
    }
    

    更新:

    您还应该在视图模型中实现System.ComponentModel.INotifyPropertyChanged 接口,并且您必须使用完整的属性才能引发PropertyChanged 事件。 ObservableCollection&lt;T&gt; 本身实现了这个接口,但是设置一个属性不会引发这个事件,除非我们引发它。

    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    
    public class RoomsViewModel : INotifyPropertyChanged
    {
        /* constructor goes here from previous code block */
    
        private ObservableCollection<AvailableRoomModel> availableRooms;
        public ObservableCollection<AvailableRoomModel> AvailableRooms
        {
            get { return availableRooms; }
            set { availableRooms = value; OnPropertyChanged(); }
        }
    
        private ObservableCollection<AvailableRoomModel> list;
        public ObservableCollection<AvailableRoomModel> List
        {
            get { return list; }
            set { list = value; OnPropertyChanged(); }
        }
    
        #region INotifyPropertyChanged implementation
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        #endregion
    }
    

    【讨论】:

    • 由于某种原因,它一直挂起。我已调试并检查列表是否已填满,确实如此。
    • 为了避免挂起房间而不是在构造函数中,而是在视图模型中的一个单独的方法,并从事件处理程序(例如Window.Loaded)中调用它,您可以使用async void作为事件处理程序和在里面你可以使用await ViewModel.LoadAvailableRooms();
    猜你喜欢
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 2019-08-07
    • 2011-01-21
    • 1970-01-01
    • 2011-11-07
    • 2013-08-29
    • 1970-01-01
    相关资源
    最近更新 更多