How to set a Timer based on a user choice? - c#

I am working on a small program and, everything works fine. Instead of having a hard coded timer though, I'd like to change the timers interval from the form from a listbox or a numericupdownbox, combobox or something along those lines.
So instead of it being a hard coded 3000MS like it is I wanted to be able to change it on the form from a small menu with 1000-10000 milliseconds.
The thing is, I am not sure how to tell the timer to use an interval specified in a optional box.
Is it possible?
Thanks.

If you're going to use a control that allows for a non-numeric input such as a TextBox ensure you validate that the input is in fact a number. Better to trap errors in the first place than deal with exceptions later.
private void SetIntervalButton_Click(object sender, EventArgs e)
{
int interval = 0;
bool success = Int32.TryParse(intervalTextBox.Text, out interval);
if(success)
{
operationTimer.Interval = interval;
}
}
You can omit the checking above if you're using a NumericUpDown control as it only allows a numeric value.
private void SetIntervalButton_Click(object sender, EventArgs e)
{
operationTimer.Interval = (int) numericUpDown1.Value;
}

You can set the interval of a timer to a value you like in the change event your your combobox.
private void ComboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
ComboBox comboBox = (ComboBox) sender;
aTimer.Interval = double.Parse(ComboBox1.SelectedValue);
}
You should use double.TryParse if you can not ensure valid data for setting the interval. If the value is being taken from a combobox and its read-only then there is no need for TryParse.

You can try:
myTimer.Interval = (int) myTextbox.Text;
You can put this in textchanged event if you want it fired every time you change the textbox value.

Related

Events in a chess clock c#

I am building af chess clock in c#. In this clock I increment with seconds for each draw. The draw comes from hitting a button. The seconds in the incrementing is chosen in a combobox 'comboboxSeconds'. I want to use this value 5, 10, 15 seconds in the button event method. How do I subscribe to the combobox event so I can use the value in the button click event.
The code is simple:
```
private void btnStartHvid_Click(object sender, RoutedEventArgs e)
{
if (Hvidantal > 1)//we do not increment in the first draw)
{
timeHvid += TimeSpan.FromSeconds(5);// Add five seconds. Must come from combobox. So it could be 5, 10 or 15
}
lblHvidAntal.Content = Hvidantal++.ToString(); //show number of draws in a label
DPtimerHvid.Stop();
DPtimerSort.Start();
}
private void comboboxSeconds_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBoxItem cbi = (ComboBoxItem)(sender as ComboBox).SelectedItem; //ok
String seconds = cbi.Content.ToString(); //seconds chosen 5, 10 eller 15
}
I assume the problem here is read the selected time from the combobox in the button-handler, so it can be used to increment the time.
Assuming wpf, you should be able to use the SelectionBoxItem property to check the selected time. I.e.
timeHvid += TimeSpan.FromSeconds((int)myCombobox.SelectedItem);
You might want to assign a name to your combobox, i.e. insert x:Name="myCombobox" in the xaml.
Also, you need to decide what type of objects you want to put into your combobox. Using strings will make it more difficult to convert the value to a time. Using int will work fine if you only want to show the numbers, and no additional text. Or you could use a custom class to store both the actual value, and override ToString to determine how the value should be displayed.

Automatic insertion of rows to DataGrid View without using a timer in Winforms

A row is to be automatically added in a datagridView of Winforms according to value changes in a text box.
A text box (textBox1) is used in the form to input the value. With the change in the value a row is to be inserted in the datagridview (dataGridView1)
I have used the following code for implementing the same,
private void timer1_Tick(object sender, EventArgs e)
{
int value;
value = Convert.ToInt32(textBox1.Text);
if(value == 2)
{
string[] row1 = {"Value is 2"};
dataGridView1.Rows.Add(row1);
}
}
The result I was expecting to get was a single row inserted in the dataGridView1.
I am getting the same row inserted a number of times since the code is running continuously inside the timer, timer1.
Can anyone help me with getting the expected result?
Can it be done without using a timer?
The usual approach would be to subscribe to the TextBox.TextChanged event:
//maybe in the form constructor
textBox1.TextChanged += HandleTextChanged;
Then you would need to implement a method HandleTextChanged somewhat like this (in the same class):
private void HandleTextChanged(object sender, EventArgs e)
{
if(int.TryParse(textBox1.Text, out var number))
{
if(number == 2)
{
string[] newRow = { "Value is 2" };
dataGridView1.Rows.Add(newRow);
}
}
}
For further information on events in WinForms, I propose you have a look at the documentation on learn.microsoft.com. Generally speaking WinForms is event-driven, so it's definitely useful to get used to the concept.
If you want to insert a new row according to the change in TextBox, you can use TextChanged event.
You delegate will be called each time the text is changed.
private void textbox_TextChanged(object sender, EventArgs e)
{
// place your code here for adding a row.
}
The textbox has a multitude of events, which you can inspect in the designer, by clicking it and selecting in the Properties window the yellow flash on the top.
if you want to add your textbox always as row when you finsihed editing the textbox,
use the apropiate event (Leave maybe) and add your row in there.
You could have your timer event tick once and then disable it:
private void timer1_Tick(object sender, EventArgs e)
{
int value;
value = Convert.ToInt32(textBox1.Text);
if(value == 2)
{
string[] row1 = {"Value is 2"};
dataGridView1.Rows.Add(row1);
}
timer1.Enabled = false; //<--disable timer1 once your job is done
}

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

Combobox cancel dropdown

I've got a combobox that opens a new form window with a datagridview, and I want the users to choose the items through that datagridview rather than through the combobox. I've got this code to achieve that:
private void comboBox1_DropDown(object sender, EventArgs e)
{
valSel.incBox = (ComboBox)sender;
valSel.Show();
if (this.comboBox1.DroppedDown)
{
MessageBox.Show("test");
SendMessage(this.comboBox1.Handle, CB_SHOWDROPDOWN, 0, 0);
}
}
As you see I'm also trying to hide the dropdown of the combobox but it isn't working. I assume it's because the combobox hasn't actually "dropped down" yet, so that part of the code is never run.
Is there an event or something I can cell when the combobox has fully "dropped down" so i can send the message to close it again?
You should be able to simply set the height of the ComboBox to something really small. Last time I looked at it, this determined the height of the popup part (the actual height of the control is determined by the UI/font size).
The more elegant way, however, would be using a custom control that just mimics the appearance of dropdown boxes (I'm rather sure that can be done some easy way).
In comboBox1.Enter set the focus to a different control if condition is met.
private void comboBox1_Enter(object sender, EventArgs e)
{
if (comboBox1.Items.Count < 1)
{
comboBox1.DroppedDown = false;
comboBox2.Focus();
MessageBox.Show("Select a list first");
comboBox2.DroppedDown = true;
}
}
1) create a KeyPress event on ComboBox from the properties.
2) write code
private void cmbClientId_KeyPress(object sender, KeyPressEventArgs e)
{
((ComboBox)sender).DroppedDown = false;
}

PopUp window on a specific time in WPF?

How can I create and show a popup window at a specific time in WPF?
What I mean how to display the window on the side of system tray.
You could use a timer if you're trying to make the thing popup in a certain number of hours/seconds/minutes (or work out how many hours/seconds/minutes are left until your specific time comes around).
private System.Windows.Threading.DispatcherTimer popupTimer;
// Whatever is going to start the timer - I've used a click event
private void OnClick(object sender, RoutedEventArgs e)
{
popupTimer = new System.Windows.Threading.DispatcherTimer();
// Work out interval as time you want to popup - current time
popupTimer.Interval = specificTime - DateTime.Now;
popupTimer.IsEnabled = true;
popupTimer.Tick += new EventHandler(popupTimer_Tick);
}
void popupTimer_Tick(object sender, EventArgs e)
{
popupTimer.IsEnabled = false;
// Show popup
// ......
}
Ok, so you also want to know how to do a notifier popup type thing, which maybe this article in CodeProject might help.
Check out this question for firing an event at a set time.
You might want to check out DispatcherTimer.

Categories

Resources