ObservableCollection を UITableView にバインドするために mvvmcross と xamarin を使用しています。コレクションは、Add、Remove、および Move メソッドを使用してその場で更新されます。これらの呼び出しは INotifyCollectionChanged イベントを正しくトリガーし、TableView は、テーブルを含むビューが最初に表示されたときに期待どおりに更新されます。ユーザーが通常のアプリケーション フローの一部として元のビューから移動し、後で正しいデータが返された場合、テーブルにロードされますが、追加、移動、および削除の呼び出しはテーブルを更新しません。
- コレクションが更新されたときに INotifyCollectionChanged イベントがまだ発生している
- MvxStandardTableViewSource のサブクラスでこれらのイベントを手動でサブスクライブし、UITableView で ReloadData を呼び出しても更新されない場合
- 私のプレゼンターは、ページにアクセスするたびにビューモデルとビューの新しいインスタンスを作成しています。
ビューをロードするカスタム プレゼンターを使用して、アプリケーションのナビゲーションにXamarin-Sidebar ( https://components.xamarin.com/view/sidebarnavigation ) も使用していますが、ビューが正確に初期化されていることがわかる限り、最初の訪問でも 2 回目以降の訪問でも同じコード パス。
私のプレゼンターの Show() メソッドは次のようになります。
public override void Show(MvxViewModelRequest request)
{
if (request.PresentationValues != null)
{
if(NavigationFactory.CheckNavigationMode(request.PresentationValues, NavigationFactory.ClearStack))
{
MasterNavigationController.ViewControllers = new UIViewController[0];
base.Show(request);
}
else if(NavigationFactory.CheckNavigationMode(request.PresentationValues, NavigationFactory.LoadView))
{
var root = MasterNavigationController.TopViewController as RootViewController;
var view = this.CreateViewControllerFor(request) as UIViewController;
root.SidebarController.ChangeContentView(view);
}
}
else
{
base.Show(request);
}
}
ViewController のバインディングは次のようになります。
public override void ViewDidLoad()
{
base.ViewDidLoad();
View.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
var source = new TracksTableSource(TableView, "TitleText Title; ImageUrl ImageUrl", ViewModel);
TableView.Source = source;
var set = this.CreateBindingSet<TracksViewController, TracksViewModel>();
set.Bind(source).To(vm => vm.PlaylistTable);
set.Apply();
}
私のビューモデルは以下のとおりです。ここで、PlaylistTable は ObservableCollection のサブクラスであり、コレクションを最新の状態に保つために追加、移動、および削除を使用して Update メソッドを使用します。
public class TracksViewModel : MvxViewModel
{
private readonly IPlaylistService _playlistService;
private readonly IMessengerService _messengerService;
private readonly MvxSubscriptionToken _playlistToken;
public PlaylistTable PlaylistTable { get; set; }
public TracksViewModel(IPlaylistService playlistService, IMessengerService messengerService)
{
_playlistService = playlistService;
_messengerService = messengerService;
if (!messengerService.IsSubscribed<PlaylistUpdateMessage>(GetType().Name))
_playlistToken = _messengerService.Subscribe<PlaylistUpdateMessage>(OnDirtyPlaylist, GetType().Name);
}
public void Init(NavigationParameters parameters)
{
PlaylistTable = new PlaylistTable(parameters.PlaylistId);
UpdatePlaylist(parameters.PlaylistId);
}
public async void UpdatePlaylist(Guid playlistId)
{
var response = await _playlistService.Get(playlistId);
PlaylistTable.Update(new Playlist(response));
}
private void OnDirtyPlaylist(PlaylistUpdateMessage message)
{
UpdatePlaylist(message.PlaylistId);
}
}
このセットアップは、ビューが最初に初期化され、テーブルが正しく更新されるときに完全に機能します。テーブルの更新に失敗するのは、ビューが初期化された 2 回目以降だけです。ビューが両方のインスタンスで同じ手法を使用して作成されているように見えるときに、バインディングが失敗する理由を誰かが説明できますか?
必要に応じて追加のコードを投稿できますが、PlaylistTable から投稿していないコードは単体テストと最初の表示で正しく機能するため、問題はプレゼンターの使用方法にあると思います。