简体   繁体   中英

Why does Windows Forms databinding want to set my nested boolean databound property when I raise a notification event on the parent object?

OK, so here is some context for my problem, written as pseudo-C# code (feel free to point out any mistake): (You can jump directly to the stacktrace and read the context later.)

public class SomeForm {
    private _model = new ViewModelClass
    public void new() {
        // Normal Winforms init omitted
        ViewModelClassBindingSource.DataSource = _model;
        SomeControl1.SetModel(_model);
    }
}
public class SomeControl {
    private _model = new ViewModelClass

    internal void SetModel(ViewModelClass model) {
        _model = model;
        ViewModelClassBindingSource.DataSource = model;
        ViewModelClassBindingSource.ResetBindings(true);
    }
}

public class ComplexObject : IPropertyChanging, IPropertyChanged {
    public property bool BoolProp {get; set;}
}

public class ViewModelClass : IPropertyChanged {
    property IList<ComplexObject> ComplexObjects {get;}

    property ComplexObject SelectedComplexObject {get; set;}

    property Object SomethingNotNecessarilyRelated {get; set;}

    private void NotifyPropertyChanged(string propName) {
        PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}

All of the mentioned properties in these classes are databound in the Visual Studio 2008 Windows Forms designer, in the SomeForm or in the SomeControl classes. ( ComplexObject.BoolProp is databound in both). Don't hesitate to ask more questions about the context.

The problem: When I make some (bunch of) notifications in the ViewModelClass class, there is some kind of knee-jerk reaction that sets ComplexObject.BoolProp to false , using that kind of stack trace:

System.dll!System.ComponentModel.ReflectPropertyDescriptor.SetValue(object component = "Object Exposed in 'SelectedComplexObject'", object value = false) + 0x124 bytes 
System.Windows.Forms.dll!System.Windows.Forms.BindToObject.SetValue(object value) + 0x5d bytes  
System.Windows.Forms.dll!System.Windows.Forms.Binding.PullData(bool reformat, bool force) + 0x15a bytes 
System.Windows.Forms.dll!System.Windows.Forms.BindingManagerBase.PullData(out bool success = true) + 0x6e bytes 
System.Windows.Forms.dll!System.Windows.Forms.BindingSource.ParentCurrencyManager_CurrentItemChanged(object sender = {System.Windows.Forms.CurrencyManager}, System.EventArgs e) + 0x54 bytes   
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.OnCurrentItemChanged(System.EventArgs e) + 0x17 bytes 
System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.List_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e) + 0x3bc bytes   
System.Windows.Forms.dll!System.Windows.Forms.BindingSource.OnListChanged(System.ComponentModel.ListChangedEventArgs e) + 0x7e bytes    
System.Windows.Forms.dll!System.Windows.Forms.BindingSource.InnerList_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e) + 0x2e bytes 
System.dll!System.ComponentModel.BindingList<System.__Canon>.OnListChanged(System.ComponentModel.ListChangedEventArgs e) + 0x17 bytes   
System.dll!System.ComponentModel.BindingList<MyCompany.ViewModelClass>.Child_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + 0x176 bytes 
[Native to Managed Transition]  
[Managed to Native Transition]  
MyCompany.Gui.exe!MyCompany.ViewModelClass.NotifyPropertyChanged(String propertyName = "SomethingNotNecessarilyRelated") Line 437 + 0x3c bytes  Basic

Why does the program want to set SomeBool to false ? And how I can prevent that?

My very first question on Stack Overflow was about a field in a Windows Forms application containing an unexpected value, like yours. The solution was to wait until the form load event was fired to set up the GUI elements of the form.

I would postpone setting up _model (including constructing it with new ) and other GUI elements until in the handler for the form load event.

HOWTO:

Add the form load handler in Visual Studio:

  1. Open the form in the graphical view (for example, double-click SomeForm.cs in Solution Explorer)

  2. Double click in the form, outside any controls or other GUI elements (for example, in the title bar). This will add skeleton code for a function named SomeForm_Load and the line this.Load += new System.EventHandler(this.SomeForm_Load); will be added the SomeForm.Designer.cs .

Move the setup code to SomeForm_Load :

private void SomeForm_Load(object aSender, EventArgs anEvent)
{
    _model = new ViewModelClass;

    ViewModelClassBindingSource.DataSource = _model;
    SomeControl1.SetModel(_model);
}

Remove " = new ViewModelClass " from the declaration of _model .

I have refactored the single ViewModelClass into SomeFormViewModel and SomeControlViewModel , and binding them to their respective classes.

Simply doing that has made the issue disappear.

I would still like a better understanding of the stacktrace that I put, though - I conjecture that the gist of the problem is that each BindingSource maintains its own information of the changes made to the object - and as both of them made changes to the same object, they did not know what was happening anymore.

Had the same issue, where changing tab in a tabcontrol would reset all my databound boolean values to "false". All non-boolean values were fine. Stack trace showed exactly the same as OP.

Tried moving around the setting of the viewmodel to Form_Load like Peter suggested, but no luck. Eventually gave up and moved all the databinding from code to setting it in the UI, by creating a data source and setting the databinding on all the control properties.

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