简体   繁体   English

MvvmCross iOS UITableView不会更新Property Changed

[英]MvvmCross iOS UITableView doesn't update on Property Changed

My table view does not update whenever its source property is changed. 每当源属性发生更改时,我的表视图都不会更新。 The code is as follows: 代码如下:

ViewController: 视图控制器:

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        View.BackgroundColor = UIColor.White;

        var table = new UITableView(new RectangleF(0, 80, Device.Width, Device.Height - 80));
        Add(table);
        var source = new MvxStandardTableViewSource(table, "TitleText SessionInfo");
        table.Source = source;

        var set = this.CreateBindingSet<JoinSessionViewController, JoinSessionViewModel>();
        set.Bind(source).To(vm => vm.AvailableServers);
        set.Apply();

        table.ReloadData();
    }

ViewModel: 视图模型:

    private readonly INetworkSessionClient _client;

    public JoinSessionViewModel(INetworkSessionClient client)
    {
        _client = client;

        _client.ServerFound += ClientOnServerFound;
        _client.BeginSearchingForServers();
    }

    private void ClientOnServerFound(object sender, ServerFoundEventArgs serverFoundEventArgs)
    {
        if (AvailableServers.Any(s => s.Identifier == serverFoundEventArgs.ServerInfo.Identifier))
            return;

        AvailableServers.Add(serverFoundEventArgs.ServerInfo);
        RaisePropertyChanged(() => AvailableServers);
    }

    private List<ServerInfo> _availableServers;
    public List<ServerInfo> AvailableServers
    {
        get { return _availableServers; }
        set { _availableServers = value; RaisePropertyChanged(() => AvailableServers); }
    }

This was a tricky one. 这是一个棘手的问题。 The culprit is this line in MvxTableViewSource: 罪魁祸首是MvxTableViewSource中的这一行:

https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxTableViewSource.cs#L56 https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxTableViewSource.cs#L56

    public virtual IEnumerable ItemsSource
    {
        get { return _itemsSource; }
        set
        {
            if (_itemsSource == value) // **** This one ****
                return;

            if (_subscription != null)
            {
                _subscription.Dispose();
                _subscription = null;
            }

            _itemsSource = value;

            var collectionChanged = _itemsSource as INotifyCollectionChanged;
            if (collectionChanged != null)
            {
                _subscription = collectionChanged.WeakSubscribe(CollectionChangedOnCollectionChanged);
            }

            ReloadTableData();
        }
    }

Since I was only adding to the list and not setting it to a new list, the setter was early returning and not firing ReloadTableData(). 由于我只是添加到列表而没有将其设置为新列表,因此setter提前返回并且未触发ReloadTableData()。 The fix was to use an ObservableCollection (or anything else that implements INotifyCollectionChanged) instead of a List. 解决方法是使用ObservableCollection(或其他任何实现INotifyCollectionChanged的方法)而不是List。

    private void ClientOnServerFound(object sender, ServerFoundEventArgs serverFoundEventArgs)
    {
        if (AvailableServers.Any(s => s.Identifier == serverFoundEventArgs.ServerInfo.Identifier))
            return;

        // CollectionChanged event is not automatically martialed to UI thread
        InvokeOnMainThread(() => AvailableServers.Add(serverFoundEventArgs.ServerInfo));
    }

    private ObservableCollection<ServerInfo> _availableServers;
    public ObservableCollection<ServerInfo> AvailableServers
    {
        get { return _availableServers; }
        set { _availableServers = value; RaisePropertyChanged(() => AvailableServers); }
    }

Note that because of my particular case, the ServerFound event is being invoked on a separate thread. 请注意,由于我的特殊情况,ServerFound事件正在一个单独的线程上调用。 That means the INotifyCollectionChanged.CollectionChanged event will also be invoked on a separate thread, so the action of adding the server to the list has to be martialed onto the main thread with InvokeOnMainThread() so that the UI will properly update. 这意味着也将在一个单独的线程上调用INotifyCollectionChanged.CollectionChanged事件,因此必须使用InvokeOnMainThread()将服务器添加到列表中的操作进行策略,以便UI正确更新。

It would be nice if CollectionChanged events would automatically be handled on the UI thread, similar to how RaisePropertyChanged() works. 如果在UI线程上自动处理CollectionChanged事件会很好,类似于RaisePropertyChanged()的工作方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM