So I am making an app in C# where it creates/edits existing .ini files. One of the features I am trying to add is that if I make changes to the .ini file via the c# app I created, and either try to close the app, open another .ini file or create a new file, it should prompt the user if they want to save the file. To accomplish this, I have a flag called dataChanged. In the TextChanged events in for the multiple textboxes, I set dataChanged = true; since changes were made to the file. However, for some reason as soon as I open the app, all the TextChange events fire up so even if I don't enter any values in the various textboxes, when I close the app, it prompts me to save the file (it shouldn't!).
App UI:
User inputs text in the textboxes.
Part of code regarding the 4 textboxes:
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) //ifrs installer
{
dataChanged = true;
}
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e) //ifrs patchfile
{
dataChanged = true;
}
private void textBox3_TextChanged(object sender, TextChangedEventArgs e)
{
dataChanged = true;
}
private void textBox4_TextChanged(object sender, TextChangedEventArgs e)
{
dataChanged = true;
}
TextChanged event fires even when you set some Text. Apparently you set some initial text when app is loading.
You can subscribe to the event mannually after you set the initial value.
textBox4.TextChanged += textBox4_TextChanged;
or unsubscribe before you set the value and subscribe after that.
textBox4.TextChanged -= textBox4_TextChanged;
textBox4.Text = "Initial Value";
textBox4.TextChanged += textBox4_TextChanged;
Sounds to me like you're programmatically setting the textBoxN.Text properties.
What you might want to do is add an if (appInitialized) around your dataChanged = true; and only set appInitialized to true after the application is loaded, perhaps in your Form_Load event. This way, the initial loading doesn't set your variable. Another option is to only register the TextChanged event after you have already set the initial values. My guess is you registered the event using the designer and as a result it's firing for those initial settings because of where the designer adds event registration. Instead do the
textBox4.TextChanged += textBox4_TextChanged;
// Etc. for each text box
yourself after the .Text properties are set. Again, perhaps in your Form_Load.
I'm guessing you are loading the ini file when the program loads and this triggers to text changed event. I suggest doing something like this.
private void Form1_Load(object sender, EventArgs e)
{
LoadData();
}
private bool _LoadingData = false;
private bool _DataChanged = false;
private void LoadData()
{
try
{
_LoadingData = true;
// Load data
}
finally
{
_LoadingData = false;
}
}
public void DataChanged()
{
if (_LoadingData == false)
{
_DataChanged = true;
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
DataChanged();
}
Related
I have a Windows Form, DataGridView and two buttons.
When I will press the button1 it changes a value of RowHeadersVisible to true.
When I will press the button2 it changes a value of RowHeadersVisible to false.
public Form1()
{
InitializeComponent();
dataGridView1.RowHeadersVisible = false;
}
private void button1_Click(object sender, EventArgs e)
{
dataGridView1.RowHeadersVisible = true;
}
private void button2_Click(object sender, EventArgs e)
{
dataGridView1.RowHeadersVisible = false;
}
I cannot find any kind of events about "RowHeadersVisible" value changing in "DataGridView" class. As I mentioned "CellFormatting" event works for this action but it appears often, almost for all kind of action made in datagridview1.
I think we might create a custom event handler in order to make different decisions.
When "RowHeadersVisible" changes the value to false I need to call another function inside "CustomEvent".
private void CustomEvent(object sender, EventArgs e)
{
SomeFunction();
}
On the other hand "DataGridTableStyle" class has the event "RowHeadersVisibleChanged".
So How to solve this problem?
.NET 4.5, you should get help.
Dissolve it in the following way.
Represents the table drawn by the System.Windows.Forms.DataGrid control at run time.
// Instantiate the EventHandler.
public void AttachRowHeaderVisibleChanged()
{
myDataGridTableStyle.RowHeadersVisibleChanged += new EventHandler (MyDelegateRowHeadersVisibleChanged);
}
// raise the event when RowHeadersVisible property is changed.
private void MyDelegateRowHeadersVisibleChanged(object sender, EventArgs e)
{
string myString = "'RowHeadersVisibleChanged' event raised, Row Headers are";
if (myDataGridTableStyle.RowHeadersVisible)
myString += " visible";
else
myString += " not visible";
MessageBox.Show(myString, "RowHeader information");
}
// raise the event when a button is clicked.
private void myButton_Click(object sender, System.EventArgs e)
{
if (myDataGridTableStyle.RowHeadersVisible)
myDataGridTableStyle.RowHeadersVisible = false;
else
myDataGridTableStyle.RowHeadersVisible = true;
}
I have two text boxes in a win forms that the user will be typing information into. I would like to clear the text box when the user start typing. I am using the TextChanged event handler, so every time I type it will erase, which makes me not able to type anything into the text box. Here is the code I am using:
private void TXTBX_HourlyRatae_TextChanged(object sender, EventArgs e)
{
TXTBX.HourlyRate.Clear();
TXTBX.HoursWorked.Clear();
}
I understand that everytime I type into the text box I will be executing this event handler, but I don't know how to go about making it execute only the first time I type into the text box.
private bool firsttime = true;
private void TXTBX_HourlyRatae_TextChanged(object sender, EventArgs e)
{
if (firsttime)
{
TXTBX.HourlyRate.Clear();
TXTBX.HoursWorked.Clear();
firsttime = false;
}
}
if you want to do it everytime you enter the textbox handle the loss focus event
private void TXTBX_HourlyRatae_LostFocus(object sender, System.EventArgs e)
{
} firsttime = true;
Move your Clear() calls into the corresponding Enter or GotFocus events.
Create a new private class member:
private bool _userHasEnteredText = false;
Only erase the text when this bool is false, then set this bool to true once you've cleared the text the first time.
When I double click on my text boxes in the designed, it creates a method auto-magically for me. Since I wish the same things to occur in any of the cases, I simply call an auxiliary method from each, like in the code below.
private void TextBox_1_TextChanged(object sender, EventArgs e)
{
TextChanged();
}
private void TextBox_2_TextChanged(object sender, EventArgs e)
{
TextChanged();
}
private void TextChanged(object sender, EventArgs e) { ... }
Now I'd like to know if there's a way (other than going into my design file (which, according to the information in it, shouldn't be attempted to) to connect the actions listeners to the same method and skip the detour via the automatically generated ones.
On the designer page go to the events tab, find the event you are looking for (TextChanged) and manually enter the name of the event handler you wish them all to use.
I usually proceed like this in my projects, if controls are not going to change at runtime (i.e. if all controls in the form are added at design time):
// this is the container's ctor
public MyForm()
{
TextBox1.TextChanged += new EventHandler(UniqueHandler);
TextBox2.TextChanged += new EventHandler(UniqueHandler);
...
TextBoxN.TextChange += new EventHandler(UniqueHandler);
}
void UniqueHandler(object sender, EventArgs e)
{
TextBox source = (sender as TextBox);
// handle the event!
}
If controls will change, it's actually quite similar, it just doesn't happen in the ctor but on-site:
// anywhere in the code
TextBox addedAtRuntime = new TextBox();
addedAtRuntime.TextChanged += new EventHandler(UniqueHandler);
MyForm.Controls.Add(addedAtRuntime);
// code goes on, the new textbox will share the handler
In the properties fold-out (most often to the right of your screen) you should have a thunder icon. That's where all the events are referable.
If you don't see the properties, select the regarded component (the text box in your case), right-mouse it and pick "properties" in the context menu.
You can do it by this way:
void btn1_onchange(object sender, EventArgs e)
{
MessageBox.Show("Number One");
}
void btn1_onchange2(object sender, EventArgs e){
MessageBox.Show("Number Two");
}
public MyForm() {
Button btn1 = new Button();
btn1.Text = "Click Me";
this.Controls.Add(btn1);
btn1.TextChange += new EventHandler(btn1_onchange);
btn1.TextChange += new EventHandler(btn1_onchange2);
}
You could do it in designer view. Instead of double-clicking on an element - go to your buttons' properties, select events tab and then put a proper handler name for adequate event. Voila!
Follow these steps:
Go to the InitializeComponent().
There are three events attached to each text box.
There you shoud be able to see the following.
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
Replace this with
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
this.textBox2.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
And then remove the method below
private void TextBox_2_TextChanged(object sender, EventArgs e)
{
TextChanged();
}
want to create a selectionRangeChanged event programatically not really getting how to do it
private void btn_10D_Click(object sender, EventArgs e)
{
double varRange = 10;
double var_Sel1 = DatesX[0].ToOADate();
Chart1.ChartAreas["ChartArea1"].CursorX.IsUserEnabled = true;
Chart1.ChartAreas["ChartArea1"].CursorX.IsUserSelectionEnabled = true;
Chart1.ChartAreas["ChartArea1"].CursorX.SelectionColor = Color.LightGray;
Chart1.ChartAreas["ChartArea1"].CursorX.SelectionStart = var_Sel1;
Chart1.ChartAreas["ChartArea1"].CursorX.SelectionEnd = varRange + var_Sel1;
Chart1.ChartAreas["ChartArea1"].CursorX.Position = varRange + var_Sel1;
Chart1.SelectionRangeChanged += new EventHandler<CursorEventArgs>(Chart1_SelectionRangeChanged);
}
void Chart1_SelectionRangeChanged(object sender, CursorEventArgs e)
{
throw new NotImplementedException();
}
thank you
For all events in C# is true that if class creator did not make extra effort to allow event firing form outside of class it is impossible to fire them.
According to MSDN
Chart.SelectionRangeChanged event Occurs when the selection start position or end position is changed.
But from my tests I can see that it is fired only if it is changed by user not program.
If I understand your intention correctly you want to handle those small buttons under your chart and btn_10D_Click method is a click handler for one of them. Try to move this line
Chart1.SelectionRangeChanged += new EventHandler<CursorEventArgs>(Chart1_SelectionRangeChanged);
to your constructor and ensure it is called once (remove it form other handlers). This will ensure your code is executed when user changes selection. If you want to execute same code for your button you should simply extract handler contents to method and call it form button click handler.
void Chart1_SelectionRangeChanged(object sender, CursorEventArgs e)
{
DoSomething(/*some arguments if you need them*/);
}
private void btn_10D_Click(object sender, EventArgs e)
{
\\your code
DoSomething();
}
I was wondering about this problem for a while, but couldn't really come up with a solution. I have 2 different event handlers calling each other recursively. As soon as event A is fired, it triggers event B which triggers event A again and so on...
Basically I want to be able to select text in a RichTextBox and show the corresponding font size in a combo box. When I choose a different font size from the ComboBox, I want it's value to be applied to the selected text.
The 2 events are:
1) The selection changed event of text inside a RichTextBox:
private void MyRTB_SelectionChanged(object sender, RoutedEventArgs e)
{
//Get the font size of selected text and select the concurrent size from the ComboBox.
}
2) The selected index changed event of a Combobox:
private void CmbFont_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Apply the chosen font size to the currently selected text of the RichTextBox.
}
What would be the best solution to make sure they each only "do their thing" and do not fire the other event in doing so?
Sometimes changing a property of a control in code fires an event unintentionally. Changing the data source of a ListBox or a ComboBox will fire the SelectedIndexChanged event, for example. Use a flag to handle this case
private bool _loading;
...
_loading = true;
// Fill the ComboBox or ListView here
_loading = false;
In the event handler do this
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading) return;
...
}
Refactor your code so that A calls DoSomethingA() and B calls DoSomethingB(). This way, if you want A to do the functionality of B you can just call DoSomethingB() and not have any recursive calls.
Just use a bool (maybe called dontFireA) and set it in A just before calling B
notifying properties (used in order to enable binding from WPF to non-WPF properies) use this technique:
public object MyProperty
{
get
{
return myField;
}
set
{
if (value != myField)
{
myField = value;
NotifyProperyChanged("MyProperty"); // raise event
}
}
}
The if (value != myField) condition prevents infinite recursion (stackoverflowexception).
In some cases (e.g. floating point numbers and inaccurate value transfers) if (Math.Abs(value - myField) > someConstant) is used instead to break the recursion.
Could you apply a similar technique to your problem?
If both events are on the same object or the owners have references to each other, you could also store a flag on each e.g.
private void OnEvent()
{
DoSomething();
}
private void DoSomething()
{
this.IsBusy = true;
// do work
// raise event
if (!other.IsBusy)
RaiseEvent();
}
I am going to make the educated guess that you are not raising Event A or Event B yourself; let's say Event A is the TextBox1.TextChanged event and Event B is the TextBox2.TextChanged event, and they have handlers like:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
...
TextBox2.Text = someString;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
...
TextBox1.Text = someOtherString;
}
In this case, the handlers are each going to raise the other textbox's TextChanged event by virtue of changing the text, leading to infinite recursion.
The first thing you can do, if you want both to run once and once only, is to mark that they're already running (changing the text of the other textbox results in that textbox's event handler running within the same call stack:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
if(handler1Running) return; //the second time through we exit immediately
handler1Running = true;
...
TextBox2.Text = "Something"; //the other event handler is invoked immediately
handler1Running = false;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
if(handler2Running) return; //the second time through we exit immediately
handler2Running = true;
...
TextBox1.Text = "Something Else"; //the other event handler is invoked immediately
handler2Running = false;
}
Now, the deepest it will go is three levels; 1's handler invokes 2's handler which invokes 1's handler again, which sees that 1's handler is already running and quits before doing anything that would deepen the recursion. Same thing if you start by changing TextBox2.
The other thing you can do is make sure you aren't trying to set the textbox to the same value that's already there. Changing from one string reference to another, even if both references are the same string value, will fire the TextChanged event. If the recursion must continue naturally but will reach a steady state, this is actually the first thing to try:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox2.Text)
TextBox2.Text = builder.ToString();
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox1.Text)
TextBox1.Text = builder.ToString();
}