Validating controls bound to different properties of the same object resets objectvalues - c#

I have a form on which all textboxes are bound to different properties of the same dataobject that implements INotifyPropertyChanged. The Forms Autovalidate is set to 'Disable' as I want to trigger the validation explicitly by calling form.ValidateChildren().
Expected:
After calling ValidateChildren all edited values should be in my dataobject.
Problem:
Only the last focused control writes it's data to the dataobject, but all other controls lose the edited values and show the old value instead.
Question:
How can I make sure that all data is validated before the controls refresh themselves?
Using Autovalidate = EnablePreventFocusChange or EnableAllowFocusChange does work but as I want to validate all at once it is not an acceptable solution for me.
Searching the internet for soutions I found an example showing the same problem but unfortunately no solution.
EDIT
After further investigation i tried this and it works:
form.BindingContext[dataobject].SuspendBinding();
form.ValidateChildren();
form.BindingContext[dataobject].ResumeBinding();
Is Pausing the Binding the standard way or are there any better solutions to fix this?

I'm not sure if this is helpful or will it be a complete answer but I had similar problem where only one value has been saved out of whole form. Here is some background explanation I found on the MS site:
http://connect.microsoft.com/VisualStudio/feedback/details/351146/binding-writevalue-does-not-update-underlying-data-source
Even SuspendBinding didn't work for me. So following the link and the information there I connected the objects via BindingSource object with RaiseListChangeEvents property set to False
Dim MyBindingSource = New BindingSource With {.DataSource = MyDataSource, .RaiseListChangedEvents = False}
MyControl.DataSource = MyBindingSource
Once this is in place you can call refer to the binding on the control and write the value manually (assuming there is just one binding) the code will look similar to:
MyControl.Bindings(0).WriteValue()
Let me know if this helps.

Related

Reset Databinding automatically in winform C#

As all of us know, if we want to bind a control in the WinForm to a property It has to be done through the fallowing way:
txtTitle.DataBindings.Add(new Binding("Text", object, "Name", true, DataSourceUpdateMode.OnPropertyChanged))
but in this case if "object" ( second argument of the Binding) changes to another one, in order to reflect change in the UI, we have to reset binding in this way:
txtTitle.DataBindings.Clear();
txtTitle.DataBindings.Add(new Binding("Text", object, "Name", true, DataSourceUpdateMode.OnPropertyChanged))
but I'm looking for a solution that does the above code snippet automatically, without the need to do it manually.
I think BindingSource might help me because it has ResetBinding() method but I'm not sure.
I'll appreciate your guides.
Thank you in advance.
EDIT:
I know how to update UI element after changing property value by implementing INotifyPropertyChanged interface, but my question is how to deal with the situation when my object that UI control is bound to its property changes, not the property itself.
.
.
.
consider this situation. I have a list of objects of a class and I want to bind my textbox to the property of this class, but based on some situations I want to change my object that is selected from that list so textbox has to be updated to reflect the new object's property value. at the current stage the only solution I can use is to delete previous binding and add new one. I want that somehow UI element be aware of the situation and shows new object's property value automatically or with smallest code as possible.
Unless I'm really not understanding your use-case, all you need is a BindingSource object between your TextBox and data object.
You don't bind your TextBox directly to your object, but to the BindingSource. All you have to do is use the DataSource and DataMember properties of the BindingSource to "switch" which object is used as the source of data for your controls.
See: MS Docs

ListViewItem.Selected - Event

I'm displaying incomplete datasets in a listview.
When an item gets selected (doubleclicked or highlighted + enterKey),
I want to open a form, that allows me to add the missing data.
I checked the doc-page of ListViewItem and found that I should probably either use .OnSelected()-Method or .Selected-Event. However my IDE(#develop) offers neither of those, just a property called Selected Adding hte System.Windows.Controls-Namespace didn't change anything, though some googling suggested otherwise.
My question is:
How can I get access to these Methods/Events or is there a workaround, i.e. a ListView-Event that offers similar functionality?
Nevermind,
I used the ListView.ItemActivate-Event.

Strange VS2010 behavior with datagrid and designer

I am working on a winforms app with a DataGridView control on it, and I am experiencing some frustrating things.
First off, I want to turn off AutoColumnGeneration, but it's not listed in the properties. No problem, I can do that with a line of code...and this is where it gets weird:
In my code, the DataGridView is inaccessible. Its like it doesnt exist on the form. Looking into this, its because the designer is declaring it as part of the InitializeComponent() method instead of where it initializes all the other controls.
Because its in the designer, any change I make there gets reversed so I can't fix this.
Is there any way to stop visual studio from doing this? I found a hack around it by using one of the datagrid columns (which ARE accessible) to create a reference to the datagridview its associated with and access it that way. It works, but its ugly and not intuitive at all.
I think I found it:
In the designer, click on the DataGridView control, and change the property of GenerateMember to true. I'm guessing it is set to false.
That property is used to do just that: hide the control from the code windows. It's useful for Labels or ToolStripSeparators that you don't need to deal with in code.
I personally use the binding source as the datasource which can even be an object and then under columns it will list all of the available columns and you can pick and choose which ones are visible as well as a slew of other options including formatting.
Click the drop down on the datasource and Add a new data source and select the necessary object, in my case an order detail object. Here is some of my designer code which is created by VS2010
this.dgvOrderDetails.DataSource = this.orderDetailBindingSource;
this.orderDetailBindingSource.DataSource = typeof(OrderDetail);
And the binding source code that sets up the data to fill the datagridview (I coded this part)
orderDetailBindingSource.DataSource = orderDetList;
Then just click the ellipses on the Columns property of the datagridview and it will have all the columns listed that are available from the object and I set the ones I want visible, the order, format etc.
As for the 2nd issue I don't think you'll have that problem once you use the designer to make the changes I listed above.
In my case, I declared a private property in the Form's partial class (the file for my code, not the Designer's file) to return the control by navigating through the Controls hierarchy.
private DataGridView MyGrid
{
get { return (DataGridView)this.Controls[0].Controls[1].Controls[0].Controls[1].Controls[0]; }
}
I agree, there ought to be a better way, such as Visual Studio Designer declaring the control like it does most other controls on the form. In the meantime, this works.
Warning!
If the form's control hierarchy is ever changed, the property's definition will have to be manually updated.
Edit
I have a better solution - at least in Visual Studio 2012.
While in the form Designer, with the DataGridView selected, open its properties and look for the GenerateMember property (under the Design node) and ensure it is set to True. Once set to True, the Designer will declare a member variable for the DataGridView control.
The strange thing is that the default value appears to be True, so I'm curious how it was changed to False? Perhaps I mis-clicked when setting the name?
By the way #LarsTech's answer is the same as this update.

Binding controls to a collection of objects

I need help with data binding. Imagine this situation. I have two classes, one named Isotope, another named Photon. Class Isotope contains BindingList Photons. I also have a static class StaticVariables, where I put BindingList Isotopes. Now, I want to make a form which will allow me to browse the list of isotopes. I created a combobox CBIsotopes, that I bound to StaticVariables.Isotopes:
CBIsotope.DataSource = StaticVariables.Isotopes;
CBIsotope.ValueMember = "IsotopeName";
CBIsotope.DisplayMember = "IsotopeName";
So far, everything works. Now I want to create a datagridview DGVPhotons that will show all the photons of the selected isotope. My first instinct was to do something along the way of
DGVPhotons.DataSource = StaticVariables.ListOfIsotopes.Photons
which of course, doesn't work. Another thing I tried is to use SelectedItem property of the ComboBox:
(1)
DGVPhotons.DataSource = (CBIsotope.SelectedItem as Isotope).Photons;
This works, but not as well as I would like. If I do it on load time, nothing happens, because ComboBox is empty. If I do it when an item is actually selected in ComboBox, then it works, but as I change the selection in ComboBox, DataGridView stays the same. The solution would be to put line (1) in SelectedIndexChanged of the ComboBox, but it seems like a brute force method to me, and I feel that my approach is fundamentally wrong... Is there some more elegant solution?
Ok, the key here is to use DataBind solution. After you change source of your element don't forget to use DataBind method after, in order to bind new data.
And also, on PageLoad event, don't forget to use IsPostBack sign in order to initialize page only when request is handled for the first time.

Binding Textboxes

I have been binding textboxes in a winform with C# to a dataset. Whenever the data doesn't validate with what the database except it silently forces the focus to remain on the textbox. How can I catch the validation error and tell the user about it (and free the focus)? The BindingSource event OnDataError isn't fired.
I had a similar problem once. The focus remained in the textbox which was binded to some numeric database field when the user modified text in a textbox and then deleted it so the text property was an empty string. I solved it with something like:
textbox.DataBindings["Text"].NullValue = "";
It solved the problem for empty inputs. I don't know if it would be of any use in your case, but I'd be also interested in more general solution.
Here's also some related question on SO:
Data-bound TextBox: can't exit
Never rely on just what "Visual studio has done for me" if you don't fully understand what it's doing. I would strongly urge you to take the time and figure out how to do what it is you want to do all by yourself (meaning without designer generated code). To get you started, there are some events on the TextBox that can help you out. Start here:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validated.aspx
Specifically the validating and validated events should be what you're looking for.

Categories

Resources