简体   繁体   中英

WPF ComboBox - change selection in bound field's setter - ComboBox selection not updated

I have a ComboBox's SelectedItem property bound to an object's field. It uses TwoWay binding, which works fine in most cases; when it loads up, the dropdown's selection is set from the field's getter, and manually changing the selection calls the field's setter.

However, sometimes I want to display a confirmation dialog. If the user clicks "No", I want the value to stay the same. Here is my code:

public A Afield
{
    get { return _afield; }
    set
    {
        SetA(value);
    }
}
public void SetA(LocationConfiguration value, bool prompt = true)
{
    if (/*selection would cause irreversible changes*/)
    {
        if (prompt)
        {
            MessageBoxResult result = Microsoft.Windows.Controls.MessageBox.Show(
                    "bla bla bla",
                    "bla",
                    MessageBoxButton.YesNo,
                    MessageBoxImage.Warning);
            if (result != MessageBoxResult.Yes)
                return;
        }
        PerformIrreversibleChanges()
    }
    _afield = value;
    NotifyPropertyChanged("Afield");
}

Everything in the codebehind works perfectly. If the user accepts, the changes are made. If the user presses "No", _afield is not modified. Other controls bound to this property show the correct value.

However, the ComboBox display does NOT revert to the value of _afield. It stays as whatever they selected, even if they rejected the change. For some reason it seems like it doesn't set the item of the combobox until after the property is set. At that point it displays what the user selected, not the correct value that persists in the codebehind.

You need to set it back because of the two-way binding your property will get updated as soon as the selection is changed so you'll need to reset it to the prev value if the user cancels the change. You can look at the RemovedItems property of the event args for getting the previous value.

I managed to fix it, but the solution is not pretty. In addition to the binding, I now have a handler for the SelectionChanged event that changes the selection back to whatever it should be. Here's the code:

private void cbox_Abox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    foreach (ComboBoxItem cbi in cbox_Abox.Items)
        if ((string)cbi.Content == BoundObject.Afield.ToString())
            cbox_Abox.SelectedItem = cbi;
}

Now, whenever I manually select the ComboBox value, it writes the value to the object via binding (like it did before), and then, using this handler, it copies the value back out of the object into the ComboBox.

For some reason, using the PropertyChanged event here doesn't update the combobox, which is why I had to call ComboBox.SelectedIndex explicitly.

Have SetA return a boolean

set
{
     if (value == _afield) return;         
     if (SetA(value)) _afield = value;
     NotifyPropertyChanged("Afield");
}

Alternatively, you could have saved the previous value and kept it as a fallback if the user pressed 'NO'

 private A previousAfield;
 public A Afield
 {
    get { return _afield; }
    set
    {
       previousAfield = _afield;
       SetA(value);
    }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM