MvvmCross iOS UITableView不会更新Property Changed
每当源属性发生更改时,我的表视图都不会更新。 代码如下:
视图控制器:
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(); set.Bind(source).To(vm => vm.AvailableServers); set.Apply(); table.ReloadData(); }
视图模型:
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 _availableServers; public List AvailableServers { get { return _availableServers; } set { _availableServers = value; RaisePropertyChanged(() => AvailableServers); } }
这是一个棘手的问题。 罪魁祸首是MvxTableViewSource中的这一行:
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(); } }
由于我只是添加到列表而没有将其设置为新列表,因此setter提前返回并且未触发ReloadTableData()。 解决方法是使用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 _availableServers; public ObservableCollection AvailableServers { get { return _availableServers; } set { _availableServers = value; RaisePropertyChanged(() => AvailableServers); } }
请注意,由于我的特殊情况,ServerFound事件正在一个单独的线程上调用。 这意味着INotifyCollectionChanged.CollectionChanged事件也将在一个单独的线程上调用,因此将服务器添加到列表的操作必须使用InvokeOnMainThread()进行主要线程的策略,以便UI正确更新。
如果在UI线程上自动处理CollectionChanged事件会很好,类似于RaisePropertyChanged()的工作方式。