WPF: Отменить пользовательский выбор в связанном с данными ListBox?

Как я отменяю пользовательский выбор в связанном с данными WPF ListBox? Исходное свойство установлено правильно, но выбор ListBox вне синхронизации.

У меня есть приложение MVVM, которое должно отменить пользовательский выбор в WPF ListBox, если определенные условия проверки перестали работать. Проверка инициирована выбором в ListBox, а не Кнопкой отправки.

ListBox.SelectedItem свойство связывается с a ViewModel.CurrentDocument свойство. Если проверка перестала работать, метод set для выходов свойства модели представления, не изменяя свойство. Так, свойство, к который ListBox.SelectedItem связывается не становится измененным.

Если это происходит, метод set свойства модели представления действительно генерирует событие PropertyChanged, прежде чем это выйдет, который я принял, будет достаточно для сброса ListBox назад к старому выбору. Но это не работает - ListBox все еще показывает новый пользовательский выбор. Я должен переопределить тот выбор и вернуть его в синхронизации с исходным свойством.

На всякий случай это не ясно, вот пример: ListBox имеет два объекта, Document1 и Document2; Document1 выбран. Пользователь выбирает Document2, но Document1 не удается проверить. ViewModel.CurrentDocument свойство все еще установлено на Document1, но ListBox показывает, что Document2 выбран. Я должен вернуть выбор ListBox к Document1.

Вот моя Привязка ListBox:

<ListBox 
    ItemsSource="{Binding Path=SearchResults, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
    SelectedItem="{Binding Path=CurrentDocument, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

Я действительно пытался использовать обратный вызов от ViewModel (как событие) к Представлению (который подписывается на событие), для сдерживания свойства SelectedItem к старому выбору. Я передаю старый Документ с событием, и это - корректное (старый выбор), но выбор ListBox не возвращается.

Так, как я возвращаю выбор ListBox в синхронизации со свойством модели представления к который SelectedItem свойство связывается?Спасибо за помощь.

24
задан David Veeneman 9 April 2010 в 16:03
поделиться

2 ответа

-snip-

Хорошо, забудьте то, что я написал выше.

Я только что провел эксперимент, и действительно, SelectedItem выходит из синхронизации всякий раз, когда вы делаете что-нибудь более причудливое в сеттере. Я полагаю, вам нужно подождать, пока сеттер вернется, а затем асинхронно изменить свойство обратно в вашей ViewModel.

Быстрое и грязное рабочее решение (проверенное в моем простом проекте) с использованием помощников MVVM Light:

                var dp = DispatcherHelper.UIDispatcher;
                if (dp != null)
                    dp.BeginInvoke(
                    (new Action(() => {
                        currentDocument = previousDocument;
                        RaisePropertyChanged("CurrentDocument");
                    })), DispatcherPriority.ContextIdle);

В вашем сеттере, чтобы вернуться к предыдущему значению CurrentDocument

                var dp = DispatcherHelper.UIDispatcher;
                if (dp != null)
                    dp.BeginInvoke(
                    (new Action(() => {
                        currentDocument = previousDocument;
                        RaisePropertyChanged("CurrentDocument");
                    })), DispatcherPriority.ContextIdle);

он, по сути, ставит изменение свойства в очередь на поток UI, приоритет ContextIdle гарантирует, что он будет ждать, пока UI не будет в согласованном состоянии.

К сожалению, это создает связь между вашей моделью представления и вашим представлением, и это уродливый хак.

Чтобы заставить DispatcherHelper.UIDispatcher работать, вам нужно сначала выполнить DispatcherHelper.Initialize().

8
ответ дан 28 November 2019 в 22:48
поделиться

Понятно! Я собираюсь принять ответ majocha, потому что его комментарий под его ответом привел меня к решению.

Вот что я сделал: Я создал обработчик события SelectionChanged для ListBox в code-behind. Да, он уродлив, но он работает. В code-behind также содержится переменная уровня модуля, m_OldSelectedIndex, которая инициализирована в -1. Обработчик SelectionChanged вызывает метод Validate() ViewModel и получает обратно булево значение, указывающее, действителен ли Документ. Если документ действителен, обработчик устанавливает m_OldSelectedIndex в текущий ListBox.SelectedIndex и выходит. Если документ недействителен, обработчик сбрасывает ListBox.SelectedIndex на m_OldSelectedIndex. Вот код обработчика события:

private void OnSearchResultsBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var viewModel = (MainViewModel) this.DataContext;
    if (viewModel.Validate() == null)
    {
        m_OldSelectedIndex = SearchResultsBox.SelectedIndex;
    }
    else
    {
        SearchResultsBox.SelectedIndex = m_OldSelectedIndex;
    }
}

Обратите внимание, что в этом решении есть хитрость: Вы должны использовать свойство SelectedIndex; это не работает со свойством SelectedItem.

Спасибо за помощь majocha, и надеюсь, это поможет кому-нибудь еще на этом пути. Например, мне, через шесть месяцев, когда я забуду это решение...

6
ответ дан 28 November 2019 в 22:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: