question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DataBinding object property to static list in ComboBox is calling EndEdit on model containing said property.

See original GitHub issue
  • .NET Core Version: .NET 5
  • Have you experienced this same bug with .NET Framework?: Haven’t tested yet, will try tomorrow.

Problem description: So I’ve been Googling this for several hours and I haven’t found much, so I’m not sure if I am doing it wrong or if this is a bug.

I have a class with a string property, this property can be one of two values, for sake of example we will say A or B:

internal class Model : IEditableObject
{
    public string TestString { get; set; } = "A";

    public void BeginEdit()
    {
        Debug.WriteLine("BeginEdit");
    }

    public void CancelEdit()
    {
        Debug.WriteLine("CancelEdit");
    }

    public void EndEdit()
    {
        Debug.WriteLine("EndEdit");
    }
}

In my form I setup a databinding for SelectedItem on TestString:

BindingSource bindingSource = new BindingSource(new Model(), "");
comboBox1.DataSource = new BindingSource(new string[] { "A", "B" }, ""); // Tried this with and without a BindingSource, probably don't need it.
comboBox1.DataBindings.Add("SelectedItem", bindingSource, "TestString");

The issue is, whenever the combobox runs it’s OnValidation call setup via the binding, it is calling EndEdit in Model even though the DataSource for the combobox is not the model, it’s supposed to be a static list.

Either I am missing something super obvious, or I’ve done something wrong, cause I am super confused. I followed the same pattern for TextBoxes and NumericUpDowns` and those work fine. Not sure yet if this only applies to .NET 5, I will check tomorrow.

Expected behavior: The property on Model should be updated and editing should not be completed.

Minimal repro: See above code snippets.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
weltkantecommented, Dec 10, 2020

If you don’t implement INotifyPropertyChanged the binding source will do it for you. In this case every write of the binding source to the model will raise the change event but without knowing which property might have changed it will pull all properties from the model just to be safe.

In simple scenarios this is fine as the values are usually the same as before, but if you have dependent bindings and event handlers at the same time it makes your life more complicated, because you have to pay attention to the order of updates you do. You can just do that (write your code being aware of the order you do things in), or if you don’t want to pay this attention you can implement INotifyPropertyChanged and take over the responibility of notifying the binding engine of which exact properties change.

Alternatively use distinct binding sources instead of sharing the binding source, this also breaks notification dependencies.

As an example, if your SelectedIndexChanged handler updates the Maximum and you fixed it to write back to the model, then model will tell all other bindings to refresh themselves in case something changed. Now if SelectedIndexChanged handler was called before the SelectedItem binding wrote back the current selection, this refresh would flip the combo box back to the old value triggering your SelectedIndexChanged recursively.

You can work around that by being order-aware or appropriately suspending bindings or using some flag to prevent recursion, there are many techniques, but personally I prefer to avoid all this complexity by implementing INotifyPropertyChange and managing dependencies between properties on the model itself.

1reaction
weltkantecommented, Dec 10, 2020

There are several things happening making everything very complicated:

  • your bindings are in OnValidation mode, that is they will write back the value to the model on validation (usually when focus leaves the control)
  • you change the Minimum immediately when the combobox selection changes; the Value of the NumericUpDown is updated but not written back because all bindings are in OnValidation mode
  • when you leave the combobox the SelectedItem is written back to the model (not the Value of the NumericUpDown because it is not the control being validated)
  • since you don’t implement INotifyPropertyChanged on your model the binding system refreshes all bindings to make sure everything is up to date after writing back the value
  • the model still has TestInteger = 1 and tries to refresh the NumericUpDown but this is no longer possible because Minimum = 50
  • the binding system catches the exception and calls EndEdit to recover from the binding error

Recommendations:

  • either turn some of your bindings to OnPropertyChange mode or make your SelectedIndexChanged handler flush relevant bindings; the way its currently written (mixing OnValidation bindings with immediate event handlers) is probably not what you intended
  • you might want to implement INotifyPropertyChanged on the model, otherwise you will have to deal with recursive refreshes
Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - Binding to ComboBox displays Model name instead of ...
I've set up the binding for a combo box using a property in the ViewModel. But when I debug the app on a...
Read more >
.NET Winforms Combobox databinding with ...
I'm running into a weird issue with databinding the Text property of a combobox to a string property of a custom object.
Read more >
Step by Step WPF Data Binding with Comboboxes
This article will teach you how to use data binding with ComboBox es. ... All data binding are based on binding to a...
Read more >
WPF Controls with MVVM: ComboBox - YouTube
Designing WPF controls, especially with MVVM, can be tricky so I ... 8:14 - ComBobox : creating, data binding and data displaying 11:44 ......
Read more >
Data Source in Blazor ComboBox Component
The ComboBox can generate its list items through an array of complex data. For this, the appropriate columns should be mapped to the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found