how to generate a SelectionRangeChanged Event Programatically ChartControl WinForms - c#

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();
}

Related

Adding a function to one button in an array of buttons

I am trying to make a calculator in C# through code only (Just adding a groupBox and a label in designer).
I have successfully added buttons a coma and a +/- sign.
But now I am running into a problem.
I can assign a function to all of them but
I need to assign a function separately to one of the buttons.
so far I have tried this with one button :
double num = Convert.ToDouble(Answer.Text);
Answer.Text = (-num).ToString();
But since I am working with arrays I have no idea how I can separate one button from another.
Essentially I should be able to do this:
If(Numbers[10].IsPressed)
do this.
but again I don't know the syntaxe's well enough
I dont really know what you want to do... But you might try a 'big' event handler... example:
Button[] buttons;
foreach(var button in buttons)
{
button.Click += MyHandler;
}
// method1
private void MyHandler(object sender, EventArgs e)
{
if(sender == buttons[0])
// Do something...
else if(sender == buttons[1])
// do something else...
else if(sender == buttons[2])
// and so on...
}
// method2
private void MyHandler(object sender, EventArgs e)
{
var button = (Button)sender;
switch(button.Text)
{
case "+":
case "1":
case "2":
// and so on...
}
}
Another good approach is having own handler for every button. Usualy Visual Studio will generate own click handler when you double click button in the designer.
private void ButtonPlus_Click(object sender, EventArgs e)
{
// Do something when "+" pressed
}
private void ButtonMinus_Click(object sender, EventArgs e)
{
// Do something when "-" pressed
}
You can manually add event handlers to the buttons in constructor (in case you used Visual Studio for generating it - Visual Studio will automatically add generated event handler to the button)
this.ButtonPlus.Click += ButtonPlus_Click;
this.ButtonMinus.Click += ButtonMinus_Click;
With approach above you will have own functions for every operations, which can help to maintain your code base little bid easily/faster.
However if you want to use only one event handler for all buttons, then you can use Button.Tag property.
Create method for every operation you have
private void ExecutePlus()
{
// Do something when "+" pressed
}
private void ExecuteMinus()
{
// Do something when "+" pressed
}
Then in constructor save all operations in the .Tag property of correspondent button.
this.ButtonPlus.Tag = ExecutePlus;
this.ButtonMinus.Tag = ExecuteMinus;
// add "general" event handler
var buttons = new[] { this.ButtonPlus, this.ButtonMinus };
foreach(var button in buttons)
{
button.Click += Button_Click;
}
Then create "general" click handler
private void Button_Click(object sender, EventArgs e)
{
var button = (Button)sender;
Action execute = (Action)button.Tag;
execute();
}
You will still have separated method for every operation, but only one event handler for all buttons

TextChanged event firing as soon as I open the app

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();
}

Is there a better way to close buttons on click?

I'm a beginner and have an assignment in which I must program the game of NIM. I begin with 15 "tokens" and at each turn a maximum of three can be removed, or "hidden". So far I am hiding these tokens on click by doing the following.
private void button1_Click(object sender, EventArgs e)
{
button1.Visible = false;
}
private void button2_Click(object sender, EventArgs e)
{
button2.Visible = false;
}
I simply copied and pasted that multiple times and changed the button numbers so that my buttons will close on click. This might be obvious, but is there a more efficient way to do this, instead of having 15 button close methods?
You can use the same click event for every single button, and make use of the sender object, casting it to Button:
private void buttonsToClose_Click(object sender, EventArgs e)
{
((Button)sender).Visible = false;
}
Then just add that handler to every single button you want to close itself on click.
Note, though, that this will throw an InvalidCastException if you or anyone else uses this handler on an object that is not a Button, so if you're actually going to use this code I would add some sort of conditional to check the real type of the sender.
Additionally, you could reuse this for any Control object by casting sender to Control instead, given that Button inherits from Control, and all Control objects have the Visible property. Here's an example, with a conditional to guard against an invalid cast:
private void controlToMakeInvisible_Click(object sender, EventArgs e)
{
if (sender.GetType() == typeof(Control))
{
((Control)sender).Visible = false;
}
}
A final note - it seems from your post like you may have a slight misunderstanding about the way events are created and wired in with objects in Windows Forms. If you go into the Designer, add a click event, and see it pop into your Form code as follows:
private void button1_Click(object sender, EventArgs e)
the name of this method has no bearing on its function. The button1 part of button1_Click doesn't actually have any logical linkage with the Button button1 - it's just the default name assigned by the Designer. The actual assignment of the method button1_Click to the Button.Click event is auto-generated into your Form's Designer.cs method.
The point of this is that if you copy and paste button1_Click and change every incidence of button1 with button2, like so:
private void button2_Click(object sender, EventArgs e)
{
button2.Visible = false;
}
it's not going to fire when button2 gets clicked. In actual fact, it's never going to fire at all, because the method hasn't actually been connected to any controls/events.
just call your event in a foreach loop.
private void Form1_Load(object sender, EventArgs e)
{
foreach (var button in Controls.OfType<Button>())
{
button.Click += button_Click;
}
}
void button_Click(object sender, EventArgs e)
{
((Control) sender).Visible = false;
}
if you change:
Controls.OfType<Button>()
to
Controls.OfType<Control>()
it will set visible to false for any Control. so you can control what item you want the event to be raised for easily.
OfType summary: Filters the elements of an IEnumerable based on a specified type.

How to connect text change event in multiple text boxes to a single method (C#)?

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();
}

2 events calling each other

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();
}

Categories

Resources