Сбросить выбранный элемент combobox на наборе с помощью MVVM

Я использую ComboBox в моем приложении WPF и после MVVM. Существует список строк, которые я хочу показать в моем ComboBox.

XAML:

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem}" />

Модель Вид:

public Collection<string> ItemsCollection; // Suppose this has 10 values.
private string _selectedItem;
public string SelectedItem
{
    get { return _selectedItem; }
    set
    {
        _selectedItem = value;
        Trigger Notify of property changed.
    }
}

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

Теперь вот чего я пытаюсь достичь. Когда я изменяю выбранный элемент из мое мнение мне нужно поставить галочку, что значение хорошо / плохо (или что-то еще) установить выбранный элемент, иначе не устанавливайте его. Поэтому моя модель представления меняется следующим образом.

public string SelectedItem
{
    get { return _selectedItem; }
    set
    {
        if (SomeCondition(value))
            _selectedItem = value;           // Update selected item.
        else
            _selectedItem = _selectedItem;   // Do not update selected item.
        Trigger Notify of property changed.
    }
}

Теперь, когда я выполняю этот код и SomeCondition (value) возвращает false, SelectedItem возвращает старое строковое значение, но, на мой взгляд, выбранный элемент в ComboBox-это значение, которое я выбрал. Поэтому предположим, что у меня есть коллекция из 10 строк, отображаемых в моем ComboBox. Все значения хороши, кроме второго и четвертого элемента (SomeCondition возвращает false для 2-го и 4-го значения). Что я хочу, чтобы, если я выберу 2-й или 4-й элемент selectedItem, не изменялись. Но мой код делает это неправильно. Если я выбираю 2-й элемент, то view по-прежнему отображает 2-й элемент как выбранный. Я знаю, что в моем коде что-то не так. Но что это?

3 ответов


это очень интересный вопрос. Во-первых, я согласен с другими ребятами, что это не рекомендуется подход к обработке недопустимого выбора. Как предполагает @blindmeis,IDataErrorInfo является одним из хороших способов его решения.

вернемся к самому вопросу. Решение, удовлетворяющее тому, что хочет @Faisal Hafeez:

public string SelectedItem
{
    get { return _selectedItem; }
    set
    {
        var oldItem=_selectedItem;
        _selectedItem=value;
        OnPropertyChanged("SelectedItem")

        if (!SomeCondition(value)) //If does not satisfy condition, set item back to old item
            Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => SelectedItem = oldItem),
                                                 DispatcherPriority.ApplicationIdle);
    }
}

Dispatcher - это элегантный способ обработки некоторой синхронизации пользовательского интерфейса во время другой синхронизации пользовательского интерфейса. Например, в этом случае необходимо сбросить выделение во время выделения обязательный.

вопрос в том, почему мы должны сначала обновить выбор. Это потому что SelectedItem и SelectedValue отдельно назначаются и какой дисплей на ComboBox не зависит от SelectedItem (может быть SelectedValue, Я не уверен здесь). И еще один интересный момент-если SelectedValue изменения, SelectedItem должно измениться, но SelectedItem не обновляет SelectedValue, когда она меняется. Таким образом, вы можете выбрать привязку к SelectedValue так что вам не нужно назначать сначала.


попробуйте изменить XAML на this

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedIndex="{Binding currSelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} " />

и в вашей VM

{
    set{ 
        currSelection = -1;
    }
}