C# Databound Windows Forms control does not retain value unless you leave the field
I saw the answer in Databound Windows Forms control does not recognize change until losing focus.
But this doesn't fully answer the question for me. I have the exact same situation. On ToolStrip_click, I go through all of my controls and I force "WriteValue()", but it still revert开发者_如何转开发s to the previous value before the save. Can anyone suggest how I can fix this? Did I implement this incorrectly?
(See code for current (non-working) solution.)
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
// Make sure that all items have updated databindings.
foreach (Control C in this.Controls)
{
foreach (Binding b in C.DataBindings)
{
// Help: this doesn't seem to be working.
b.WriteValue();
}
}
}
The code is now much simpler, but it is a considerable hack. I'd be very happy to know if there is a more "proper" fix for this.
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
// Make sure that all text fields have updated by forcing everything
// to lose focus except this lonely little label.
label44.Focus();
}
The problem is probably that your databound controls are set to update on validation.
You need to set the DataSourceUpdateMode of each of the databound controls to DataSourceUpdateMode.OnPropertyChanged. For example, a databound textbox:
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text",
this.someBindingSource, "SomeProperty", true,
System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
You can also set the datasource update mode in the designer by :
Selecting the control and going to the Property Window -> (DataBindings) -> (Advanced)
-> Set the [Data Source Update Mode] in the dropdownlist to OnPropertyChanged.
cheers
A ToolStripButton does not take the Focus when clicked. You could add some code to (temporarily) focus another control. You can Focus a Label (as a neutral dummy).
What are you binding to? If it's a DataSet, DataTable, etc., or better yet, a BindingSource, you should call EndEdit:
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
// Assuming that you are binding to bindingSource1:
bindingSource1.EndEdit();
}
I implement an ISave
interface on my forms to handle dirty state and saving and whenever the dirty state is checked (whenever IsDirty is called), I always EndEdit on my binding source:
interface ISave
{
bool IsDirty;
bool Save(bool force);
}
With this interface, when, say, the application is shutting down, I can easily iterate through my open MdiChild windows checking to see if any information has been saved by casting the child form to ISave
and checking the value of IsDirty
. Here, I call EndEdit on either the appropriate binding source or, if applicable, the binding control (for example, a grid).
And forgive the ramble, but I thought this might be helpful. The rest works like so:
Save()
takes a parameter of "force", so I can have a "Save & Close" button a form (saves the user an extra click or confirmation asking if they want to save their changes). If force is false, the Save()
method is responsible for asking the user if they want to save. If it's true, it's assumed the user has already decided they definitely want to save their information, and this confirmation is skipped.
Save()
returns bool- true if it's safe to continue executing the calling code (presumably a Form_Closing event). In this case, (if force was false), given a YesNoCancel MessageBox, the user either selected Yes or No and the save itself did not throw an error. Or, Save()
returns false in the event the user chose Cancel or there was an error (in other words, telling the calling code to cancel a form close).
How you handle the errors depends on your exception-catching conventions - this could either be caught in the Save()
method and displayed to the user or perhaps in an event such as FormClosing where e.Cancel
would then be set to true.
Used with a form closing event it would look like this:
private void form1_FormClosing(object sender, CancelEventArgs e)
{
if (IsDirty)
e.Cancel = !Save(false);
}
Used with a forced save from a Save & Close button, it would look like this:
private void btnSaveAndClose_Click(object sender, EventArgs e)
{
if (IsDirty)
if (Save(true))
Close();
}
Anyway, a little more than you asked for, but I hope this helps!
Try this:
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
// Make sure that all items have updated databindings.
foreach (Control C in this.Controls)
{
C.SuspendLayout();
foreach (Binding b in C.DataBindings)
{
// Help: this doesn't seem to be working.
b.WriteValue();
}
C.ResumeLayout();
}
}
This has stumped me in the past. In addition to the DataSourceUpdateMode being set to OnPropertyChanged, the underlying column in the data source must not be read only.
Check it for your column in a DataTable:
dataTable.Columns("ColumnName").ReadOnly
I even made a function that sets all columns to not be ReadOnly, which has come in handy more than once:
Public Function MakeReadOnlyFalse(ByVal dt As DataTable) As DataTable
For Each col As DataColumn In dt.Columns
If col.ReadOnly Then
col.ReadOnly = False
End If
Next
Return dt
End Function
For me this is worst. If i set the update source mode to OnPropertyChanged on combobox, it behave just like if i had set this to Onvalidation mode! Bindings are far more better in wpf.
精彩评论