Let's say we have a Win32 form with a Save toolbar button and some sontrols like a CheckBox are on the form, now we write a one line code for onchange event of checkbox to enable/disable the Save button. Let's say checkbox is selected at first, Save button disabled, now de-select the checkbox, Save button becomes enabled...now select the checkbox again Save button is still enabled...Same for a TextBox for example. Let's say its text is "Hi"...change it to "Hi Bye" , Save is enabled...change it BACK to "Hi" as it was, Save remains enabled...
Is there a model we can use to prevent these wrong enabling/disabling of save button?
You need to write some IF - ELSE code in the CheckedChanged event of the Checkbox. Check what is the current state by inspecting the Checked proeprty of the control (checkbox) ,If yes set the Enabled proeprty of the Button to true, else false.
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
if (checkBox2.Checked)
button1.Enabled = true;
else
button1.Enabled = false;
}
Assuming checkBox2 is the name of the Checkbox and button1 is the name of the Save button.
You can use the same IF ELSE logic for other controls also. To Set the Value of the Textbox, Use the Text property
TextBox1.Text="I am gonna try something now"l
EDIT : As comecme suggested, If you only want to enable/disable button based on the checbox, It can be done in one line instead of the IF else block like this
button1.Enabled=checkBox2.Checked
You could store the last saved state, and compare the current state to it whenever it changes, to see if they're identical. If so, disable the button.
If these comparisons are expensive, you could make this more efficient, by calculating a hash value over all of the fields that need to be saved, and only doing the proper comparison if the hash of the last saved state matches the hash of the current state.
I prefer to put all my control state checking and setting into a single method:
private void UpdateControls()
{
saveButton.Enabled = checkBox1.Checked;
otherButton.Visible = checkBox2.Checked && textBox.Text.Length > 0;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
UpdateControls();
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
UpdateControls();
}
private void textBox_TextChanged(object sender, EventArgs e)
{
UpdateControls();
}
This means you just have one place in which to check and set the state, and makes it much easier to understand what is going on, especially when you have complex forms. I also prefer boolean expressions rather than if statements when assigning boolean variables, because it caters for both true and false without having to write a separate else statement (which may be forgotten).
I don't get where you're going with your checkbox, but I would use a Boolean variable:
private Boolean _canSave = false;
private Boolean CanSave
{
get { return _canSave; }
set
{
_canSave = value;
MenuSave.Enabled = value;
}
}
public void MenuSave_Click()
{
Save();
}
private void Save()
{
// do your thing
CanSave = false;
}
public void TextBox_TextChanged()
{
CanSave = true;
}
This won't account for disabling the saving menu when you revert the text back to its original. If you want that, you'll have to store the text in the Save() method in a private variable, and compare that to the current text on every TextBox_TextChanged() to determine whether a change compared to the original (i.e. since last save) has occurred.
Related
I am making a Windows Forms application with algorithms for school and I want to add some nice functionality to display that the algorithm is working well. One of those things is that when the user selects an item in one listbox, the items that are part of that one item get automatically selected in another listbox. This is done by the application.
I would like it if the user could not select another item in the listbox that is automatically monitored, but enabled = false sets the color to gray which makes the text invisible when an item is automatically selected.
Is there any other way to achieve this?
What you could do is
When the program selects an entry in the second list, set a flag
When an entry in the list is selected, read that flag
If the flag is not set, unselect the item
Unset the flag
Code wise, this equates to something like the following (please note that I would not write code like this in a real-world szenario, but to get the gist of it, it should suffice)
private bool _valueIsSetProgrammatically = false;
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
this._valueIsSetProgrammatically = true;
this.listBox2.SelectedItem = this.listBox1.SelectedItem;
}
private void listBox2_SelectedValueChanged(object sender, EventArgs e)
{
if (!this._valueIsSetProgrammatically)
{
this.listBox2.SelectedItem = null;
}
this._valueIsSetProgrammatically = false;
}
Please note that this snippet unselects the second listbox. If you'd like to retain the selected item, you could change the second method to
private void listBox2_SelectedValueChanged(object sender, EventArgs e)
{
if (!this._valueIsSetProgrammatically)
{
this.listBox2.SelectedItem = this.listBox1.SelectedItem;
}
this._valueIsSetProgrammatically = false;
}
(Technically the flag is not needed in this case, you could simply set the SelectedItem of listBox2 to the SelectedItem of listBox1.)
I am trying to make the save button visible when text is entered into the text box by using the following code:
if (tbName.TextModified == true)
{
btnCTimetablesOk.Visible = true;
}
else
{
btnCTimetablesOk.Visible = false;
}
but it gives error at tbname.textmodified
is there any other way to visible the button when we enter the text in text box
this is error i am getting "the event textbox.textmodified can only appear on the left hand side of += or -="
Try using the textbox's Enter and Leave events to show/hide your button:
private void textBox1_Enter(object sender, System.EventArgs e)
{
btnCTimetablesOk.Visible = true;
}
private void textBox1_Leave(object sender, System.EventArgs e)
{
btnCTimetablesOk.Visible = false;
}
Then modify your textbox to use these new methods.
If I'm reading your text correctly, you want the save button to be visible when the textbox has text in it and invisible when the text box is blank. If that's the case, you can use the Leave event (which occurs when the textbox loses focus) and a simple if statement:
private void textBox1_Leave(object sender, System.EventArgs e)
{
if(textBox1.Text != "")
btnCTimetablesOk.Visible = true;
else
btnCTimetablesOk.Visible = false;
}
You can also put this conditional block in any other methods kicked off by events that change the text of the box.
Also, you might want to consider using Enabled instead of Visible, it'll leave the button on the form but will gray out the text and clicking will do nothing.
I'm going to take a stab in the dark here and assume that the button is related to the textbox and you probably want someone to be able to type something in the textbox then click the button. You probably don't want the user to have to type something, then tab out or click somewhere else to make the button visible then click the button.
tbName_TextChanged(object sender, EventArgs e)
{
btnCTimetablesOk.Visible = !String.IsNullOrEmpty(tbName.Text)
}
Btw you're getting that error because TextModified isn't a boolean property, it's an event, like TextChanged or Leave or Enter. You can assign an event handler to it but you can't just check it like that.
As an aside I personally hate systems hungarian for winforms controls. I'd much rather have a timetablesOkButton than a btnCTimeablesOK button. That way if you also have a timetablesNameTextBox you can see at a glance that the button and the textbox match. Of course it may not be up to you.
I have a form that is linked to a database and allows a user to insert, update and delete records. I want the user to be notified of any unsaved changes when they click to go back to the main menu, and have the option whether or not to save them.
The code I have so far is below, but it doesn't recognize the changes. It just goes straight back to the main menu.
private void btnBack_Click(object sender, EventArgs e)
{
frmMenu frmMainMenu = new frmMenu();
if (dsOrders.HasChanges())
{
if (DialogResult.Yes == MessageBox.Show("There are changes that have not been saved and will be lost. Would you like to save them before leaving this form?", "Unsaved Changes", MessageBoxButtons.YesNo))
{
dsOrders.AcceptChanges();
}
else
{
frmOrders.ActiveForm.Hide();
frmMainMenu.Show();
}
}
else
{
frmOrders.ActiveForm.Hide();
frmMainMenu.Show();
}
}
I am guessing you are using DataBinding and dsOrders is a dataset.
What you could try to do is to check if your databinding is working correctly (both-ways) by setting a breakpoint just before the menu is called.
Then, you could edit some data, and when the breakpoint is triggered, check if the changes are in the dataset. If they are not, the HasChanges method will return false, and you won't get the messagebox.
An other way to check if your data has changed to show this message would be to attach an eventhandler on the change event of all the controls on your form. In this event handler you could set a boolean like blnChanged to true and check its value instead of dsOrders.HasChanges
One way to do is use the individual controls' Changed event and set a dirty bit
for eg
public bool Dirty { get; set; }
private void textBox1_TextChanged(object sender, EventArgs e)
{
Dirty = true;
}
and then
if (Dirty)
{
if (DialogResult.Yes == MessageBox.Show("There are changes that have not been saved and will be lost. Would you like to save them before leaving this form?", "Unsaved Changes", MessageBoxButtons.YesNo))
{
dsOrders.AcceptChanges();
}
else
{
frmOrders.ActiveForm.Hide();
frmMainMenu.Show();
}
}
I am building a WinForms Application in C# .NET
The WinForms Application has a ComboBox where the DropDownStyle is set to DropDownList. When the App is launched, I read an XML file to populate the values of the ComboBox. And, at this time, nothing is selected in the ComboBox by default. As a result, buttons Change and Delete are disabled.
Now, when the user selects a value, I want the buttons Change and Delete to be enabled. So far I have accomplished (although, I am not sure that I have done it in the right way).
I have written the code in the SelectionChangeCommitted Event.
private void cbList_SelectionChangeCommitted(object sender, EventArgs e)
{
if (cbList.SelectedItem != null)
{
this.btnModify.Enabled = true;
this.btnRemove.Enabled = true;
}
else
{
this.btnModify.Enabled = false;
this.btnRemove.Enabled = false;
}
}
Now, when I chose a value...the buttons get enabled (as expected). The user then clicks on Delete button and we remove the selected value. Now, there is nothing Selected in the cbList but the buttons are still enabled?
What is the function/event where I check if a value is selected or not and then enable/disable the buttons.
At the moment, dont have Visual Studio, so I dont remember which events we have. But you can make this,
private void CheckButtons()
{
if (cbList.SelectedItem != null)
{
this.btnModify.Enabled = true;
this.btnRemove.Enabled = true;
}
else
{
this.btnModify.Enabled = false;
this.btnRemove.Enabled = false;
}
}
and use your func in event
private void cbList_SelectionChangeCommitted(object sender, EventArgs e)
{
CheckButtons();
}
as you said, after deleting, buttons are still visible, so you can put CheckButtons() function after your delete function like
DeleteX();
CheckButtons();
I have a combobox at the top of a form that loads editable data into fields below. If the user has made changes, but not saved, and tries to select a different option from the combobox, I want to warn them and give them a chance to cancel or save.
I am in need of a "BeforeValueChange" event with a cancelable event argument.
Any advice on how to accomplish?
Save the ComboBox's SelectedIndex when to box if first entered, and then restore it's value when you need to cancel the change.
cbx_Example.Enter += cbx_Example_Enter;
cbx_Example.SelectionChangeCommitted += cbx_Example_SelectionChangeCommitted;
...
private int prevExampleIndex = 0;
private void cbx_Example_Enter(object sender, EventArgs e)
{
prevExampleIndex = cbx_Example.SelectedIndex;
}
private void cbx_Example_SelectionChangeCommitted(object sender, EventArgs e)
{
// some custom flag to determine Edit mode
if (mode == FormModes.EDIT)
{
cbx_Example.SelectedIndex = prevExampleIndex;
}
}
Here is the simplest fix:-
bool isSelectionHandled = true;
void CmbBx_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (isSelectionHandled)
{
MessageBoxResult result = MessageBox.Show("Do you wish to continue selection change?", this.Title, MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.No)
{
ComboBox combo = (ComboBox)sender;
isSelectionHandled = false;
if (e.RemovedItems.Count > 0)
combo.SelectedItem = e.RemovedItems[0];
return;
}
}
isSelectionHandled = true;
}
Save the current value on the Enter event.
Implement the BeforeValueChange logic in the ValueChanged event, before the actual ValueChanged logic. If the user cancels, set the stored value and don't continue in the method (return).
If you're going to use this system a lot, I'd suggest inheriting ComboBox and implementing your BeforeValuechange event there.
The Validating event can be used for this scenario
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx
You don't get an appropriate event by default. You could cache the previous value and set it back to that if the user wants to cancel.
How about using the Validating / Validated events?
It works well, if the event happening on LostFocus instead of Change is ok with you.
Otherwise, how about
public void Combobox_ValueChanged(object sender, EventArgs e) {
if (!AskUserIfHeIsSureHeWantsToChangeTheValue())
{
// Set previous value
return;
}
// perform rest of onChange code
}
You could use a message filter to intercept clicks and key presses, which would allow you to prevent the combo box's normal behaviour. But I think you'd be better off disabling the combo box when the user makes a change, and require them to either save or revert their changes.
You can't really prevent it, but you can change it back to the old value if certain requirements aren't met:
private SomeObject = selectedSomeObject=null;
private void cbxTemplates_SelectionChangeCommitted(object sender, EventArgs e)
{
if (!(sender is ComboBox cb)) return;
if (!(cb.SelectedItem is SomeObject tem)) return;
if (MessageBox.Show("You sure?", "??.",
MessageBoxButtons.OKCancel) != DialogResult.OK)
cb.SelectedItem = selectedSomeObject;
else
{
selectedSomeObject = tem;
}
}