Binding error in design and runtime on usercontrol - c#

In great need help with the strange binding problem with regards to Winform UserControls.
Its like this.
Have a form with a UserControl
UserControl has a System.Windows.Forms.BindingSource control
BindingSource has a DataSource set to an entity POCO type at design time.
UserControl has controls that are bound to properties on the POCO class. An example: CreateDate
No problem in designer of the UserControl itself.
But entering the designer og the Form containing the UserControl, I get a designer error window with the message: "Cannot bind to the property or column CreateDate on the DataSource. Parameter name: dataMember"
In runtime I get the same error, but first when Show is called on the form. Here I can see on the stack trace that it is thrown after a CheckBinding call.
The error occurs no matter if the DataSource on the bindingSource is set or not during the creation (in constructor) or Load event on the form.
I can see that the designer sets my data source like this in the designer file: this.bindingSourceRecipe.DataSource = typeof(Data.Entities.Recipe);
I have tried so many things to solve this problem. It seems very strange as this is a dead simple form/control setup and should be a trivial use of Winforms usercontrols.
If I set the bindingSourceRecipe.DataSource at runtime to a temp. instance just after the InitializeComponent() in the form then no error occure;
InitializeComponent();
ucRecipeBaseControl.Recipe = new Recipe() { Id = 0, CreateDate = DateTime.Now, Name = "" };
So it seems that the Initialization cycle of the form/control somehow clears the binding source knowledge about its DataSource type.
This does of course not happen if a place all the user controls and BindingSource Directly on the form. Then everythings works, and it does not matter if the DataSource ever gets set to an instance of a Data entity.
Seems like a complete mystery to me, should be dead simple, and I'm kind of lost on what to do.
Any help or suggestions are highly appreciated.
BR Peter Meldgaard

Ahhh, got it nailed at last. It was caused by a mix of Winform designer behavior and my code. I was setting the binding controls datasource in a public property setter, so I could save a copy of the entity, to be able to compare the changed and the org. The thing is that when you put a control with a public property on a form, then the designer initializes this property to null inside the designer generated code. I did not know that. So everytime the usercontrol was instantiated, the DataSource got set to null, clearing the typeof(dataentity), albeit loosing the binding information.
Adding a null check in the setter, and only update datasource when value is not null fixed the issue.

Related

How to prevent designer column replication when using extended DataGridView control that adds columns?

I am creating a DataGridView inherited control that performs some stylizations and also adds a number of columns. The problem is that when this control is added to another form, the designer sees that the Columns property does not match its default value and so adds column generation to the designer in the new form.
To illustrate the problem. Take the following control:
class CustomDataGridView : DataGridView
{
public CustomDataGridView()
{
Columns.Clear();
Columns.Add("Column", "Header");
}
}
The Columns.Clear() is unnecessary - it's just there to illustrate that the problem is not the constructor. Anyhow, add the control it to a form. Cause the form UI to reload (by e.g. resizing the datagridview) and the designer ends up constantly adding a new column. I've tried a variety of ideas with no result. I attempted to hide the columns property from the designer, but unfortunately as it's not virtual that's also a no go.
Any ideas? I feel like I must be missing something simple since this is presumably a fairly common usage pattern. I could just add the columns at runtime, but ideally I'd like to keep them visible/editable in the designer.
The idea I mentioned in the question does actually seem to work fine just using not-really-hiding the property hiding:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new DataGridViewColumnCollection Columns { get => base.Columns; }
That solves all the issues of wanting to be able to see and interact with the columns in the designer and since the columns in this control are not intended to be modified it's acceptableish - but is there a way to actually add columns without a hack like this?

How to verify control's databinding match the bindingsource?

I have complex forms where controls are on various tabs and panels. These forms use a bindingsource to bind their controls to the data source.
There might be situations during development where the data source's members have been renamed but not the forms' controls.
As no exception is thrown on loading the form, is there a way to loop through the bindingsource's datasource members and compare them with the controls' databinding values?
Particular attention must be made to hidden controls, as explained in this SO answer.
Where should this check take place? In the constructor or OnLoad? (It should at least happen after InitializeComponent because the bindingsource's datasource, ie. typeof(myObject) is set in this method).
The binding object has the event bindingcomplete which could help you to get the statut (sucess-error) of a binding operation (read-write).
Don't forget to enable the formatting on the databinding. Without that the event is not raise.
https://msdn.microsoft.com/en-us/library/k26k86tb(v=vs.100).aspx
As the purpose of Databinding is to "link" business object property to graphical control property, the hidden control won't "read" the value until the control become visible. You should access directly the business databoundobject, instead of the reading the property of a UI control.
Wrapping your Load with a Try Catch is also a good thing (in every case), because exception thrown in this event are silently catched by Winforms. This could make the form to be loaded and visible with only half of your "loading process code".

Control's default properties

When I add a control to a form through the designer, not all properties of the control appear in the designer code. For example, when I add a ListBox the UseWaitCursor property does not appear in the designer code unless it is set to True. When I change it to False it disappears from the designer code, which makes me think that the properties somehow have defaults and don't appear in the designer code if left at default.
Can someone please help me understand how the designer works and where all this is tracked. The reason I ask is I am currently writing a class that extends a third party ActiveX control which I plan to initialize dynamically at run time. I was going through the designer code (when the third party control is added through the designer) and a lot of its properties do not appear there.
This is done with the [DefaultValue] attribute. The Control.UseWaitCursor property looks similar to this:
[DefaultValue(false)]
public bool UseWaitCursor
{
// etc..
}
So if you leave the value at False in the Properties window then the designer knows that it should not display the value in Bold and that it is not necessary to put the property assignment in the InitializeComponent() method since the default is already good. An ActiveX control will certainly have a lot of properties set at its default value as well.

How to save control property from designer auto-filling? [duplicate]

This must be a FAQ, but I can’t find a duplicate question!
There are lot of different attributes that control what the WinForm Designer does with properties on a custom control, I am never clear on the one I should use in this case.
I am looking for:
Designer does not show property in grid
Designer does not read value of property
Designer does not set property to default value
E.g. Designer behaves as if the property was not there.
Designer does not complain if it has already done one of the above before the attributes were added (hard!)
Background.
The code that is giving me the problem is:
this.eventListControl.FilterSets =
((SystList<FilterSet>)(resources.GetObject("eventListControl.FilterSets")));
The FilterSets property should never have been touched by the winforms designer; it is now not Serializable and MsDev falls over every time a form that used the eventListControl is changed!
I think you can use [Browsable (false)] and [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
The second attribute prevents the property from appearing in InitializeComponent

Prevent from generating Form.resx

I have a form that inherits from another from. In the designer, whenever I adjust something like control size or location, VS auto-generates a resx file for that form. The resx just contains some KeyValuePairs for comboboxes, w/c are unnecessary really since these values are already defined in the parent class.
Aside from this, the designer.cs also gets update w/ inherited properties such as Text, NumericUpDown.Value, DisplayMember, ValueMember, etc, w/c again are already defined in the parent class.
I know the designer.cs is supposed to be update w/ the new location and size, but I don't want it to update other stuff that's inherited from parent class.
Is there a way to prevent this, and just let the designer update the location and size?
UPDATE:
I found that the ComboBox.Items.AddRange() gets added to the Designer.cs and .resx file due to binding logic that I have in OnLoad(). This is primarily preventing the designer to load properly when the form is reloaded on the Designer.
I modified OnLoad to run the binding logic only when DesignMode is false.
The form no longer throws errors when reloading the designer, but some of the control properties are still unnecessarily added back to the Designer.cs whenever I change any property via the property dialog.
UPDATE2:
Totally prevented the designer from generating unnecessary control properties by applying suggestion here.
Now all that's generated are control location and size.

Categories