Используя ReactiveUI / DynamicData, я не могу понять, как установить SelectedItem
ComboBox после обновления ItemSource
. Я использую SourceList<T>
для хранения изменяемой коллекции вместе с Connect / Bind / Subscribe для обновления ReadOnlyObservableCollection
, который связан с ComboBox.ItemSource
.
ComboBox
связан так в представлении:
this.OneWayBind(ViewModel, vm => vm.EventYearsList, v => v.EventYearsComboBox.ItemsSource).DisposeWith(d);
this.Bind(ViewModel, vm => vm.SelectedEventYear, v => v.EventYearsComboBox.SelectedItem).DisposeWith(d);
Во ViewModel я определяю ReactiveCommand
для обновления SourceList
, SourceList
для хранения данных, возвращаемых из сервисного уровня, ReadOnlyObservableCollection
, который связан на ComboBox.ItemSource
и свойство для хранения SelectedItem
.
public ReactiveCommand<Unit, Unit> GetEventYearsListCommand { get; }
private readonly SourceList<short> _eventYearsSourceList = new SourceList<short>();
private readonly ReadOnlyObservableCollection<short> _eventYearsList;
public ReadOnlyObservableCollection<short> EventYearsList => _eventYearsList;
private short? _selectedEventYear;
public short? SelectedEventYear
{
get => _selectedEventYear;
set => this.RaiseAndSetIfChanged(ref _selectedEventYear, value);
}
В конструкторе ViewModel я настроил подписки:
GetEventYearsListCommand = ReactiveCommand.CreateFromTask(ExecuteGetEventYearsListCommand);
GetEventYearsListCommand.ThrownExceptions.Subscribe(ex => Trace.WriteLine(ex.ToString()));
_eventYearsSourceList
.Connect()
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(out _eventYearsList)
.Subscribe();
// when a series is selected, this fires off the command to update the event years
this.WhenAny(x => x.SelectedSeries, _ => Unit.Default)
.ObserveOn(RxApp.MainThreadScheduler)
.InvokeCommand(GetEventYearsListCommand);
Обратите внимание, что эта команда вызывается, когда пользователь меняет выбранный элемент на другой ListBox
...
И, наконец, команда для обновления SourceList
выглядит следующим образом:
private async Task ExecuteGetEventYearsListCommand()
{
var eventYearsList = new List<short>();
if (SelectedSeries != null)
{
eventYearsList = await seriesApi.QueryEventYears(SelectedSeries.OrgSeriesPath);
}
_eventYearsSourceList.Edit(list =>
{
list.Clear();
if (eventYearsList != null) list.AddRange(eventYearsList);
});
// This trace shows the correct number of items in the list
Trace.WriteLine($"_eventYearsSourceList count = {_eventYearsSourceList.Count}");
// But here, I don't get the right count, EventYearsList has not been updated yet!!!
Trace.WriteLine($"EventYearsList count = {EventYearsList.Count}");
// and this check isn't even valid, because EventYearsList hasn't been updated...
if (EventYearsList?.Count > 0)
{
SelectedEventYear = EventYearsList.First();
}
}
Итак, глядя на команда непосредственно выше ... Я обновил SourceList
, но ReadOnlyObservableCollection
еще не обновился ... Он по-прежнему показывает содержимое SourceList
до моего обновления.
Первая проблема, я даже не получаю первый элемент из недавно обновленного списка, потому что он еще не был обновлен.
T Вторая проблема заключается в том, что, даже если я установлю выбранный элемент прямо сейчас, этот выбор теряется, когда EventYearsList наконец обновляется. Из-за привязки twoway к выбранному элементу (я предполагаю), SelectedEventYear
устанавливается равным нулю после того, как EventYearsList наконец обновляется. Так что даже если бы я мог установить выбранный элемент прямо сейчас, он был бы перезаписан. (Я подтвердил это поведение, установив точку останова в установщике свойств SelectedEventYear)
Либо я делаю что-то не так ... Или мне нужно найти способ (отдельно) подключить что-то, что говорит мне, когда основной источник для ReadOnlyObservableCollection
изменился.
Итак, вернемся к первоначальному вопросу ... Как мне установить SelectedItem
ПОСЛЕ обновления на ItemSource
?