private void CheckBox_CheckedChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
SetValuesInDB( System.Security.Principal.WindowsIdentity.GetCurrent().Name,
DateTime.Today.Date);
}
Now I want to setvalues of my id and current date in database only if I directly clicked on the checkbox.
I dont want to update those values in Database if some other event triggers this event handler.
For eg: while loading everytime the checkbox gets checked but the database value for this checkbox is unchecked.
so, everytime this event handler is triggered and database value is updated.
How do I take care of it?
Use the CheckBox.Click event instead. It gets fired if either the user clicks on the checkbox or uses Space to toggle the checkbox.
I'm not really sure what you want to do.
If you want the value in the database and userinterface to be always up to date you might try DataBindings...
internal class MyDataSource {
public bool MyBooleanValue {
get { return ReadValueFromDB("MyUser", "MyBool"); }
set { SaveValueToDB("MyUser", value); }
}
}
...
internal class MyControl {
internal MyControl() {
dataSource = new MyDataSource();
InitializeComponents();
myCheckbox.DataBindings.Add(
"Checked", dataSource, "MyBooleanValue"
);
}
private MyDataSource dataSource;
}
otherwise you might wish to write the value only in the database when the user finishes an operation. Such as closing event handler of a form or okButton click event handler.
Related
I have a CheckBox that has it's Checked property bound to a bool value. During the CheckedChanged event, some logic runs which uses the bool property on the data source.
My problem is the first time the CheckBox gets checked by the user, the bound data source does not get updated. Subsequent updates work fine though.
Here's some sample code for testing the problem. Just create a blank form and add a CheckBox to it.
public partial class Form1 : Form
{
private bool _testBool;
public bool TestBool
{
get { return _testBool; }
set { _testBool = value; }
}
public Form1()
{
InitializeComponent();
checkBox1.DataBindings.Add(new Binding("Checked", this, "TestBool"));
checkBox1.CheckedChanged += new EventHandler(checkBox1_CheckedChanged);
}
void checkBox1_CheckedChanged(object sender, EventArgs e)
{
checkBox1.BindingContext[this].EndCurrentEdit();
Debug.WriteLine(TestBool.ToString());
}
}
The first time I check the box, the TestBool property remains at false, even though checkBox1.Checked is set to true. Subsequent changes do correctly update the TestBool property to match checkBox1.Checked though.
If I add a breakpoint to the CheckedChanged event and check out checkBox1.BindingContext[this].Bindings[0] from the immediate window, I can see that modified = false the first time it runs, which is probably why EndCurrentEdit() is not correctly updating the data source.
The same thing also occurs with using a TextBox and the TextChanged event, so this isn't limited to just CheckBox.Checked.
Why is this? And is there a generic common way of fixing the problem?
Edit: I know of a few workarounds so far, although none are ideal since they are not generic and need to be remembered everytime we want to use a Changed event.
setting the property on the datasource directly from the CheckedChanged event
finding the binding and calling WriteValue()
hooking up the bindings after the control has been loaded
I am more concerned with learning why this is happening, although if someone knows of a standard generic solution to prevent it from happening that does not rely on any special coding in the Changed event, I'd be happy with that too.
Controls usually want to go through their validation first before writing to the data source, so the writing of the value usually won't happen until you try to leave the control.
You can force the writing of the value yourself:
void checkBox1_CheckedChanged(object sender, EventArgs e) {
Binding b = checkBox1.DataBindings["Checked"];
if (b != null) {
b.WriteValue();
}
Debug.WriteLine(TestBool.ToString());
}
Apparently, the CheckedChanged event is too early in the process.
But you can leverage BindingComplete:
public partial class Form1 : Form
{
private Boolean _testBool;
public Boolean TestBool
{
get { return _testBool; }
set { _testBool = value; }
}
public Form1()
{
InitializeComponent();
checkBox1.DataBindings.Add(new Binding("Checked", this, "TestBool", true, DataSourceUpdateMode.OnPropertyChanged));
checkBox1.DataBindings[0].BindingComplete += Form1_BindingComplete;
}
private void Form1_BindingComplete(Object sender, BindingCompleteEventArgs e)
{
Debug.WriteLine("BindingComplete: " + TestBool.ToString());
}
}
Note that the event will fire at startup as the initial bind linkage occurs. You will have to deal with that possible unintended consequence, but otherwise, it works on the first click and every click.
Also note that the true (format) is required in the Binding constructor to make the event fire.
The closest I can find for an explanation to this behavior is this 3rd party explanation
Basically, this is an issue of timing. The way binding works in DotNet
is actually very simple. There's no magic in the DotNet framework that
tells the BindingManager when something changes. What it does is, when
you bind to a property (such as CheckedValue) The BindingManager looks
for an event on the control called propertynameChanged (e.g.
"CheckedValueChanged"). This is the same event your code is hooking
into on your sample form.
When the control fires the event, the order in which the listeners
receive the event is arbitrary. There's no reliable way to tell
whether the BindingManager will get the event first or the Form will.
My CheckBox1_CheckChanged event is running before the BindingManager handles the changed event, so the data source hasn't been updated at this time.
My best guess as to why this only happens the first time is that the control isn't visible yet, so some code doesn't get run that should fix the order events get handled in. I've seen other posts about not being able to bind to non-visible items due to the handle not being created yet, and one answer states
Until the control is visible for the first time some back-end initialization never happens, and part of that initialization is enabling the data binding.
So I suspect that this is somehow related.
I can verify that if I attach the Changed handler later on such as during the Load event, it works as I would expect.
public partial class Form1 : Form
{
private bool _testBool;
public bool TestBool
{
get { return _testBool; }
set { _testBool = value; }
}
public Form1()
{
InitializeComponent();
checkBox1.DataBindings.Add(new Binding("Checked", this, "TestBool"));
Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
checkBox1.CheckedChanged += new EventHandler(checkBox1_CheckedChanged);
}
void checkBox1_CheckedChanged(object sender, EventArgs e)
{
// Not needed anymore
//checkBox1.BindingContext[this].EndCurrentEdit();
Debug.WriteLine(TestBool.ToString());
}
}
Essentially I need the same thing that Form.ShowDialog() offers, but with a UserControl.
Inside a winform, I load a UserControl, which should allow a user to select an item from a list, and return it back to the caller.
For example:
var item = myUserControl.SelectItem();
Obviously, returning from a control's method is very simple. But how can I make it wait until user performs the required action with the control?
I can subscribe to an event of the control, but this path is not ideal.
Put simply, I want a UserControl's method to return after user clicks a specific button on it.
Simply put, a UserControl is really just a custom control and just like you drop a TextBox or a ListBox on your WinFrom, you drop your UserControl on the form.
Treat your UserControl just like you would treat any other control, like TextBox or ListBox.
So, just like you get the value from a TextBox through TextBox.Text or the SelectedValue or SelectedItem from a ListBox, you would call a method from your UserControl to return the SelectedItem.
Often times when the OK button is clicked or the form is closed is when in your code you would go through each of your form's controls getting their values. Presumably, you would do some validation to make sure proper values were entered, too.
Therefore, when your form is accepted is when you would call your UserControl's method to get the selected item. You don't have to subscribe to an event to wait for that to happen. Again, just treat it like you would treat a normal ListBox.
EDIT:
Knowing now more about the nature of your question this is my answer:
Say you have a UserControl that looks like this:
In the code behind you are going to have to set up an Event to monitor when the the OK button has been clicked inside the UserControl. This event will also notify a subscriber what the choice was that the user selected in your list:
public partial class SelectFromListUserControl : UserControl
{
public class SelectedItemEventArgs : EventArgs
{
public string SelectedChoice { get; set; }
}
public event EventHandler<SelectedItemEventArgs> ItemHasBeenSelected;
public SelectFromListUserControl()
{
InitializeComponent();
}
private void btnOK_Click(object sender, EventArgs e)
{
var handler = ItemHasBeenSelected;
if (handler != null)
{
handler(this, new SelectedItemEventArgs
{ SelectedChoice = listBox1.SelectedItem.ToString() });
}
}
}
On your main form you will have code patterned similar to the following.
There should be a routine to create or make visible this special user control.
It will hook the event in the user control so that the main form will be notified.
It will draw the user control.
The event handler will retrieve the value selected in the user control and then clear the user control and/or bring up another user control.
private void ShowSelectFromListWidget()
{
var uc = new SelectFromListUserControl();
uc.ItemHasBeenSelected += uc_ItemHasBeenSelected;
MakeUserControlPrimaryWindow(uc);
}
void uc_ItemHasBeenSelected(object sender,
SelectFromListUserControl.SelectedItemEventArgs e)
{
var value = e.SelectedChoice;
ClosePrimaryUserControl();
}
private void MakeUserControlPrimaryWindow(UserControl uc)
{
// my example just puts in in a panel, but for you
// put your special code here to handle your user control management
panel1.Controls.Add(uc);
}
private void ClosePrimaryUserControl()
{
// put your special code here to handle your user control management
panel1.Controls.Clear();
}
Embed it in a form and call the form modally (ShowDialog)?
But how can I make it wait until user performs the required action with the control?
The question is more about how to wait for the user to select item and click OK button without blocking entire user interface.
The answer is simple: Async/Await feature.
private readonly SelectCompletionSource as new TaskCompletionSource(of ResultType)
public async function SelectItemAsync() as ResultType
me.Visible = true
return await SelectComplectionSource.Task
end function
public function OK() as boolean
me.Visible = false
dim Result = me.SelectedItem
SelectComplectionSource.
SetResult(Result)
end function
To get an Item one calls
dim Item = await UserControl.SelectItemAsync
UserControl is shown to the user without blocking user interface. The selection task is started but paused until the result is ready.
By clicking OK button, user invokes OK function that queries selected item and makes selection task into completed state.
I have a comboxbox (okay, in real a have a ToolStripComboBox) where I want a cancleable event that is triggered under certain conditions:
Focus lost
Focus gained
Item selected from the box
pressing Enter
so a "normal" validation event, but when I do the following
this.speedSelector.Validating
+= new System.ComponentModel.CancelEventHandler(this.speedSelector_Validating);
This event is only triggered, when I try to close the application via [X]. Also I can't leave the application when a not valid text is present, that works, but how to trigger that event on my conditions above?
Regards,
You will probably need to store the initial value somewhere (like maybe in the Control's universal Tag field).
You could validate the control on any of the events: SelectedIndexChanged, SelectionChanged, TextUpdate, etc.
The value stored in the control should not change when the control gains or loses focus.
public Form1() {
InitializeComponent();
speedSelector.Tag = speedSelector.Text;
speedSelector.SelectedIndexChanged += new System.EventHandler(this.speedSelector_Changed);
speedSelector.SelectionChangeCommitted += new System.EventHandler(this.speedSelector_Changed);
speedSelector.TextUpdate += new System.EventHandler(this.speedSelector_Changed);
}
private void speedSelector_Changed(object sender, EventArgs e) {
if (validData(speedSelector.Text)) {
speedSelector.Tag = speedSelector.Text;
} else {
speedSelector.Text = speedSelector.Tag.ToString();
}
}
private static bool validData(string value) {
bool result = false;
// do your test here
return result;
}
Validating will be called when moving focus from a control on the dialog that has the CausesValidation property set to true to another control that has the CausesValidation property set to true, e.g. from a TextBox control to the OK button. Maybe your validation happens when you close the window because you have CausesValidation set on the window, and not on the appropriate controls?
You could also just move all the validation into an OnBlur event for your control and do it that way.
Please read my question its not a duplicate one.
I've three radio buttons on windows form and all these buttons have common 'CheckedChanged' event associated. When I click any of these radio buttons, it triggers the 'CheckedChanged' event twice.
Here is my code:
private void radioButtons_CheckedChanged(object sender, EventArgs e)
{
//My Code
}
I inserted the breakpoint and the whole code within this event iterates twice.
Please tell me why it is behaving like this?
As the other answerers rightly say, the event is fired twice because whenever one RadioButton within a group is checked another will be unchecked - therefore the checked changed event will fire twice.
To only do any work within this event for the RadioButton which has just been selected you can look at the sender object, doing something like this:
void radioButtons_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
if (rb != null)
{
if (rb.Checked)
{
// Only one radio button will be checked
Console.WriteLine("Changed: " + rb.Name);
}
}
}
To avoid it, just check if radioButton is checked
for example:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if (radioButton1.Checked)
//your code
}
CheckedChanged is raised whenever the Checked property changes. If you select a RadioButton then the previously selected RadioButton is unchecked (fired CheckedChanged), and then the new RadioButton is checked (fired CheckedChanged).
It's triggering once for the radio button transition from checked to unchecked, and again for the radio button transitioning from unchecked to checked (i.e. any change in checked state triggers the event)
You could set the AutoCheck property true for each RadioButton then catch the Click event instead of the CheckChanged event. This would ensure that only one event is fired, and the logic in the handler can cast the sender to type RadioButton if needed to process the click. Often the cast can be avoided if the handler logic is simple. Here is an example which handles three controls, rbTextNumeric, rbTextFixed and rbTextFromFile:
private void rbText_Click(object sender, EventArgs e)
{
flowLayoutPanelTextNumeric.Enabled = rbTextNumeric.Checked;
txtBoxTextFixed.Enabled = rbTextFixed.Checked;
flowLayoutPanelTextFromFile.Enabled = rbTextFromFile.Checked;
}
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
int click = 0;
private void radioButton1_Click(object sender, EventArgs e)
{
click++;
if (click %2==1)
{
radioButton1.Checked = true;
}
if (click %2==0)
{
radioButton1.Checked = false;
}
if (radioButton1.Checked==true)
{
label1.Text = "Cheked";
}
if (radioButton1.Checked==false)
{
label1.Text = "Uncheked";
}
}
}
}
The other answers are correct but miss the reason for the underlying problem.
When a radio button is checked the first event sent is the change from the unchecked item
however if you check its state by its control name you will still see its old checked status because the form has not been updated yet. To see its true status you need to cast the sender object.
This allows you to perform any actions relating to the condition which is being deselected should you need to do so.
In the not uncommon scenario below multiple radio buttons are sent to the same handler event.
Simply checking the state of the sender for checked will not work here as we need to perform different actions depending on which radio button has been pressed.
So first we ignore any sender that has just been unchecked.
then we identify the checked sender by control name to process the correct action.
private void ModeChangedExample(object sender, EventArgs e)
{
// multiple radio buttons come here
// We only want to process the checked item.
// if you need to something based on the item which was just unchecked don't use this technique.
// The state of the sender has not been updated yet in the form.
// so checking against rdo_A check state will still show it as checked even if it has just been unchecked
// only the sender variable is up to date at this point.
// To prevent processing the item which has just been uncheked
RadioButton RD = sender as RadioButton;
if (RD.Checked == false) return;
if (rdo_A.Name == RD.Name)
{
//Do stuff
}
if (rdo_B..Name == RD.Name)
{
// Do other stuff
}
if (rdo_C.Name == RD.Name)
{
// Do something else
}
}
This problem of double checking happens when there is a series of RadioButton Clicks in succession.I had this same problem.The last click will give two results.To overcome this i made a dummy click in the end.The double click stopped.Try this method.
Venkatraman
I have a GridView which is populated from a database, and includes a textbox. Through the code behind, I want to subscribe the textbox on each row to a certain event, but only if a field of the row matches some if statement.
So I have the following:
protected void grdRates_RowDataBound(object sender, GridViewRowEventArgs e)
{
TextBox txt = (TextBox)e.Row.FindControl("txtValue");
DataRowView dataView = (DataRowView)e.Row.DataItem;
if ((bool)dataView["isAuto"])
{
txt.AutoPostBack = true;
txt.TextChanged += new EventHandler(txt_TextChanged);
}
}
protected void txt_TextChanged(object sender, EventArgs e)
{
//Other stuff here
}
The problem is, the text changed event never fires - the AutoPostBack property is being set, as the page posts back when they move out of the TextBox, but the text changed event does not fire. Am I missing something here?
You should change the implementation so that you are not adding an event handler at the time of data binding, which will get you in all sorts of problems with the page lifecycle.
Instead, you could bind the AutoPostBack property declaratively and just set the event handler there as well.
<asp:TextBox ID="SomeInput" runat="server" ...
AutoPostBack='<%# (bool)Eval("IsAuto")'
OnTextChanged="SomeInput_TextChanged" />
The event will only fire automatically (i.e. when the input loses focus) when IsAuto == true, but it may still fire when the user clicks another button in the same row and the text in the input was changed. So you need an extra check in the event handler:
protected void SomeInput_TextChanged(object sender, EventArgs e)
{
TextBox input = (TextBox)sender;
if(input.AutoPostBack)
{
// Other stuff here
}
}
Notice that by declaratively binding we need to worry less about page life cycle, and we can use the bound property of the input to check against in the event handler.