Отмена выбора в выпадающем списке в WPF с MVVM - PullRequest
25 голосов
/ 18 октября 2011

В моем приложении WPF есть поле со списком:

<ComboBox  ItemsSource="{Binding CompetitorBrands}" DisplayMemberPath="Value" 
   SelectedValuePath="Key" SelectedValue="{Binding Path=CompMfgBrandID, Mode=TwoWay,
   UpdateSourceTrigger=PropertyChanged}" Text="{Binding CompMFGText}"/>

Привязано к коллекции KeyValuePair<string, string>

Вот свойство CompMfgBrandID в моей ViewModel:

public string CompMfgBrandID
{
    get { return _compMFG; }
    set
    {    
        if (StockToExchange != null && StockToExchange.Where(x => !string.IsNullOrEmpty(x.EnteredPartNumber)).Count() > 0)
        {
            var dr = MessageBox.Show("Changing the competitor manufacturer will remove all entered parts from the transaction.  Proceed?",
                "Transaction Type", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            if (dr != DialogResult.Yes)
                return;
        }

        _compMFG = value;
        StockToExchange.Clear();

        ...a bunch of other functions that don't get called when you click 'No'...
        OnPropertyChanged("CompMfgBrandID");
    }
}

Если вы выберете «да», он будет вести себя как положено.Элементы очищаются, а остальные функции вызываются.Если я выберу «Нет», он вернется и не очистит мой список или не вызовет какие-либо другие функции, что хорошо, но в поле со списком все еще отображается новый выбор.Мне нужно, чтобы вернуться к исходному выбору, как будто ничего не изменилось, когда пользователь выбирает «Нет».Как я могу сделать это?Я также попытался добавить e.Handled = true в коде позади, но безрезультатно.

Ответы [ 12 ]

0 голосов
/ 27 декабря 2014

Я думаю, что проблема в том, что ComboBox устанавливает выбранный элемент в результате действия пользователя после установки значения привязанного свойства.Таким образом, элемент Combobox изменяется независимо от того, что вы делаете в ViewModel.Я нашел другой подход, при котором вам не нужно сгибать шаблон MVVM.Вот мой пример (извините, что он скопирован из моего проекта и не совсем соответствует приведенным выше примерам):

public ObservableCollection<StyleModelBase> Styles { get; }

public StyleModelBase SelectedStyle {
  get { return selectedStyle; }
  set {
    if (value is CustomStyleModel) {
      var buffer = SelectedStyle;
      var items = Styles.ToList();
      if (openFileDialog.ShowDialog() == true) {
        value.FileName = openFileDialog.FileName;
      }
      else {
        Styles.Clear();
        items.ForEach(x => Styles.Add(x));
        SelectedStyle = buffer;
        return;
      }
    }
    selectedStyle = value;
    OnPropertyChanged(() => SelectedStyle);
  }
}

Разница в том, что я полностью очищаю коллекцию элементов, а затем заполняю ее элементами, сохраненными ранее.,Это заставляет Combobox обновляться, так как я использую универсальный класс ObservableCollection.Затем я устанавливаю выбранный элемент обратно на выбранный элемент, который был установлен ранее.Это не рекомендуется для многих предметов, потому что очистка и заполнение комбинированного списка довольно дорогие.

0 голосов
/ 12 октября 2013

Я сделал это аналогично тому, что сплинтор имеет выше.

Ваш взгляд:

<ComboBox  
ItemsSource="{Binding CompetitorBrands}" 
DisplayMemberPath="Value" 
SelectedValuePath="Key" 
SelectedValue="{Binding Path=CompMfgBrandID, 
Mode=TwoWay,
UpdateSourceTrigger=Explicit}" //to indicate that you will call UpdateSource() manually to get the property "CompMfgBrandID" udpated 
SelectionChanged="ComboBox_SelectionChanged"  //To fire the event from the code behind the view
Text="{Binding CompMFGText}"/>

Ниже приведен код для обработчика событий "ComboBox_SelectionChanged" из файла кода за представлением. Например, если вы просматриваете myview.xaml, имя файла кода для этого обработчика событий должно быть myview.xaml.cs

private int previousSelection = 0; //Give it a default selection value

private bool promptUser true; //to be replaced with your own property which will indicates whether you want to show the messagebox or not.

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox comboBox = (ComboBox) sender;
            BindingExpression be = comboBox.GetBindingExpression(ComboBox.SelectedValueProperty);

            if (comboBox.SelectedValue != null && comboBox.SelectedIndex != previousSelection)
            {
                if (promptUser) //if you want to show the messagebox..
                {
                    string msg = "Click Yes to leave previous selection, click No to stay with your selection.";
                    if (MessageBox.Show(msg, "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) //User want to go with the newest selection
                    {

                        be.UpdateSource(); //Update the property,so your ViewModel will continue to do something
                        previousSelection = (int)comboBox.SelectedIndex;  
                    }
                    else //User have clicked No to cancel the selection
                    {
                        comboBox.SelectedIndex = previousSelection; //roll back the combobox's selection to previous one
                    }
                }
                else //if don't want to show the messagebox, then you just have to update the property as normal.
                {
                    be.UpdateSource();
                    previousSelection = (int)comboBox.SelectedIndex;
                }
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...