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:
Open the form in the graphical view (for example, double-click SomeForm.cs
in Solution Explorer)
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.