Textbox delay events - c#

I have an option form where the user has to enter parameters for a mini-game, going from 8 to 32. My problem is that as soon as I start typing, if I insert a number under 8 (I want to put 20, for example), the event activates as soon as I type 2 and turn it into 8.
private void TXBheight_TextChanged(object sender, EventArgs e)
{
if(int.Parse(TXBheight.Text) < 8)
{
TXBheight.Text = "8";
}
else if (int.Parse(TXBheight.Text) > 32)
{
TXBheight.Text = "32";
}
}
Is there any easy way to make a delay, or wait until I finish typing?
For those who identify this question as a possible duplicate, i took a look, and the possible answers are from 6 years ago. During that time, languages and compilers evolve, so maybe there is something new we can all learn from

Instead of using a TextChanged event, use the TextBox _Validating event and the _Validated event. The _Validating event is fired only when the text box loses focus, i.e., when the user clicks on another control, e.g., a Button or another TextBox. When this happens, the _Validating event is fired and you test the value in the text box. If it's invalid, you cancel the _Validating event. If its valid, you DON'T cancel the _Validating event, and as a a result the _Validated event is fired. In the _Validated event, you do what you neeed to do when the input data is valid. Use an errorprovider to inform the user when the input data is invalid.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
errorProvider1.SetError(TXBheight, "");
//NEW NEW NEW
buttonCancel.CausesValidation = false;
}
private void Button1_Click(object sender, EventArgs e)
{
// do what is needed when the button is clicked
}
private void TXBheight_Validating(object sender, CancelEventArgs e)
{
errorProvider1.SetError(TXBheight, "");
if (String.IsNullOrEmpty(TXBheight.Text))
{
errorProvider1.SetError(TXBheight, "Height is a required field");
e.Cancel = true;
return;
}
if (int.Parse(TXBheight.Text) < 8)
{
errorProvider1.SetError(TXBheight, "Height must be GE 8");
e.Cancel = true;
return;
}
if (int.Parse(TXBheight.Text) > 32)
{
errorProvider1.SetError(TXBheight, "Height must be LE 32");
e.Cancel = true;
return;
}
}
private void TXBheight_Validated(object sender, EventArgs e)
{
//this event is fired when the data is valid, i.e.,
// if e.Cancel in the _Validating method is NOT set to cancel
}
//NEW NEW NEW
private void ButtonCancel_Click(object sender, EventArgs e)
{
AutoValidate = AutoValidate.Disable;
Close();
}
// NEW #2
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
DialogResult result = MessageBox.Show("Do you really want to exit?", "Dialog Title", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
Environment.Exit(0);
}
else
{
e.Cancel = true;
}
}
else
{
e.Cancel = true;
}
}
}

The simple answer is:
(C# 7 style)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.textBox1.TextChanged += TextBox1_TextChanged;
this.textBox1.Leave += TextBox1_Leave;
}
private void TextBox1_TextChanged(object sender, EventArgs e)
{
string text = this.textBox1.Text;
if (!int.TryParse(text, NumberStyles.Integer, CultureInfo.CurrentCulture, out int number))
{
this.textBox1.Text = "";
return;
}
if (number > 32)
{
this.textBox1.Text = "32";
}
}
private void TextBox1_Leave(object sender, EventArgs e)
{
string text = this.textBox1.Text;
if (!int.TryParse(text, NumberStyles.Integer, CultureInfo.CurrentCulture, out int number))
{
this.textBox1.Text = "8";
return;
}
if (number > 32)
{
this.textBox1.Text = "32";
}
if (number < 8)
{
this.textBox1.Text = "8";
}
}
I standardly do this with controlling the pressed keys and text changes (inclusive paste) to check correct content of the window. Unfortunately I have the code only for Borland C++ Builder and VS6 at work. Recreating this code is not that simple (too much code), therefore only the simple answer.

Use Microsoft's Reactive Framework and this becomes easy. Just do this:
private void Form1_Load(object sender, EventArgs e)
{
IObservable<long> query =
Observable
.FromEventPattern<EventHandler, EventArgs>(
h => TXBheight.TextChanged += h,
h => TXBheight.TextChanged -= h)
.Select(x => Observable.Timer(TimeSpan.FromMilliseconds(250.0)))
.Switch()
.ObserveOn(this);
IDisposable subscription = query.Subscribe(ep =>
{
if (int.Parse(TXBheight.Text) < 8)
{
TXBheight.Text = "8";
}
else if (int.Parse(TXBheight.Text) > 32)
{
TXBheight.Text = "32";
}
});
}
Now there is a 250.0 millisecond delay after the last character is typed before your code runs. If a new character is typed before the 250.0 milliseconds is up then a new timer starts and the old one doesn't fire.
The .ObserveOn(this) code marshalls the timer back to the UI thread.
Just NuGet "System.Reactive" and "System.Reactive.Windows.Forms". Also add using System.Reactive.Linq; at the top of your class.

You can use the return as your breakpoint, when the user hit enter then you run your code.
You can use that with the KeypressEvent.
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
char ch = e.KeyChar; // Getting the Key that was pressed
if (ch == 13) // Checking if it equal to 13 ASCII code for return
{
if (int.Parse(textBox1.Text) < 8)
{
textBox1.Text = ""; // emptying the textbox
textBox1.AppendText("8"); // using AppendText() to keep the cursor at the end
}
else if (int.Parse(textBox1.Text) > 32)
{
textBox1.Text = "";
textBox1.AppendText("32");
}
e.Handled = true; // To say that the event was handled.
}
}

Why not create task and check if it is completed before executing?
private Task task; //declare it at the top
private void TXBheight_TextChanged(object sender, EventArgs e)
{
if(task?.Status == TaskStatus.Running) return;
task = Task.Run( () =>
{
if(int.Parse(TXBheight.Text) < 8)
{
TXBheight.Text = "8";
}
else if (int.Parse(TXBheight.Text) > 32)
{
TXBheight.Text = "32";
}
});
}

Related

How to pause for loop when pause button is clicked?

When I run the program and try to click the pause button, nothing happens. I am not sure how I can get this to work exactly. I have a bool variable called pause and pause is set to false. Once the pause button is clicked it should set that variable to true. Then the loop checks for that and should display a message to the user. Any help is greatly appreciated!
namespace Practice2
{
public partial class Form1 : Form
{
photocopier printer = new photocopier(500, 2500);
bool pause = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnStart_Click(object sender, EventArgs e)
{
if (checkText(txtNumberCopies.Text) == true)
{
int numberCopies = Convert.ToInt32(txtNumberCopies.Text);
int toner = Convert.ToInt32(lblTonerAmount.Text);
int paperCapacity = Convert.ToInt32(lblPaperAmount.Text);
if (toner <= 625 && paperCapacity <= 125)
{
txtMessage.Text = "Printer is low on Toner and Paper!";
}
else if (toner <= 625){
txtMessage.Text = "Printer Toner is low!";
}
else if (paperCapacity <= 125)
{
txtMessage.Text = "Printer Paper is low!";
}
else
{
txtMessage.Text = "Printing...";
txtMessage.Refresh();
for (int i = numberCopies; i != 0; i--)
{
int paper = Convert.ToInt32(lblPaperAmount.Text);
paper--;
if (paper == 480 || paper == 380 || paper == 400 || paper == 200)
{
MessageBox.Show("There is a paper Jam! Please remove the Jam and then hit the ok button to continue!", "Important Message", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
if (pause == true)
{
MessageBox.Show("Press the ok button when ready to continue", "Important Message", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
lblPaperAmount.Text = Convert.ToString(Convert.ToInt32(lblPaperAmount.Text) - 1);
lblTonerAmount.Text = Convert.ToString(Convert.ToInt32(lblTonerAmount.Text) - 1);
Thread.Sleep(1000);
}
txtMessage.Text = "Job is completed!";
}
}
}
private void btnAddPaper_Click(object sender, EventArgs e)
{
int paperAmount = Convert.ToInt32(lblPaperAmount.Text);
if (checkText(txtAddPaper.Text) == true && paperAmount <= 500)
{
lblPaperAmount.Text = Convert.ToString(paperAmount + Convert.ToInt32(txtAddPaper.Text));
}
else
{
txtMessage.Text = "Printer paper is at capacity!";
}
}
private bool checkText(string textBox)
{
if (textBox.Equals("") || textBox == null)
{
txtMessage.Text = "Please enter a value in the text box!";
return false;
}
return true;
}
private void btnReplaceToner_Click(object sender, EventArgs e)
{
lblTonerAmount.Text = Convert.ToString(printer.Toner);
}
private void btnPauseCancel_Click(object sender, EventArgs e)
{
pause = true;
}
}
}
The problem is that you're doing the work on the UI thread, so the UI thread is busy and can't process messages (e.g. button click). You need to do the work on a worker thread instead, using BackgroundWorker or Task.Run for instance.
A for loop is on the UI Thread so while the for loop is running you can't do anything with the UI. I suggest that you use a System.Windows.Forms.Timer to do the job. You set the interval to 1 and that will run pretty quickly, but not as quickly as a for loop, though. But interval = 1 is enough for you.
Let me show you:
Timer timer = new Timer () {Interval=1};
to create a new timer object.
enter
timer.Tick +=
in the constructer and press TAB twice and that should generate an event handler. Write the stuff you want to do in the event handler.
Call timer.Stop to pause the timer and timer.Start to start the timer.

Track whether a user typed an specific "word" on an WinForm

I've a ScreenLocker winform application. It's full-screen and transparent. It unlocks the screen when user presses Ctrl+Alt+Shift+P.
But I want it more dynamic. I would like to let a user set his own password in a config file.
For example, he set his password mypass. My problem is- how can I track whether he typed 'mypass' on that form?
I don't want to have any textbox or button on the form. Help please.
Here is my current code-
public frmMain()
{
InitializeComponent();
this.KeyPreview = true;
this.WindowState = FormWindowState.Normal;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Bounds = Screen.PrimaryScreen.Bounds;
this.ShowInTaskbar = false;
double OpacityValue = 4.0 / 100;
this.Opacity = OpacityValue;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.P && e.Modifiers == (Keys.Control | Keys.Shift | Keys.Alt))
{
this.Close();
}
}
You can store the typed letters in a variable, then check it on enter keydown event. Here is the working sample-
public partial class Form1 : Form
{
String pass = String.Empty;
public Form1()
{
InitializeComponent();
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
string value = e.KeyChar.ToString();
pass += value;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode==Keys.Enter)
{
//Now check the password with your config file.
//You may have to reset the variable if the pass does not match with the config.
}
}
}
I think the most elegant and robust solution is to use the reactive extension framework.
PM> Install-Package Rx-Main
Key pressed are stored in a buffered observable sequence. When the buffer matches the password an action is taken (in the example it's a message box)
private void Form1_Load(object sender, EventArgs e)
{
string password = "test";
var keypressed = Observable.FromEventPattern<KeyPressEventHandler, KeyPressEventArgs>(
handler => handler.Invoke,
h => this.KeyPress += h,
h => this.KeyPress -= h);
var keyDownSequence = keypressed.Select(p => p.EventArgs.KeyChar);
var checkPasswordSequence = from n in keyDownSequence.Buffer(password.Length, 1)
where string.Join("", n.ToArray()) == password
select n;
checkPasswordSequence.Subscribe(x => MessageBox.Show(string.Join("", x.ToArray())));
}
This is working
public partial class LockScreen : Form
{
Timer checkTimer;
string curPass = "";
string pass = "mypass"; // take it from your config file
public LockScreen()
{
InitializeComponent();
this.KeyPreview = true;
this.WindowState = FormWindowState.Normal;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Bounds = Screen.PrimaryScreen.Bounds;
this.ShowInTaskbar = false;
double OpacityValue = 4.0 / 100;
this.Opacity = OpacityValue;
// Add a keypress event
this.KeyPress += LockScreen_KeyPress;
checkTimer = new Timer();
checkTimer.Interval = 1000;
checkTimer.Tick += checkTimer_Tick;
}
void LockScreen_KeyPress(object sender, KeyPressEventArgs e)
{
checkTimer.Stop();
curPass += e.KeyChar.ToString();
if (curPass == pass)
this.Close();
else
checkTimer.Start();
}
void checkTimer_Tick(object sender, EventArgs e)
{
curPass = ""; //resets every second
}
}
private const string Password = "Foobar";
private readonly StringBuilder _builder = new StringBuilder();
private void LockForm_KeyPress(object sender, KeyPressEventArgs e)
{
//Check if the key pressed is a control character (e.g. alt/enter et cetera)
//and return if that is the case
//Also make sure to reset the stringbuilder's buffer now and then,
//if too much input is generated
_builder.Append(e.KeyChar);
if (_builder.ToString().EndsWith(Password))
{
//Correct password has been entered
}
}

Change Label text to what is written, when ListView as active object

When I click on my ListView and write "this text!", I want my Label (or TextBox if that's easier) to change text to "this text!".
How can I do this?
You can use the AfterLabelEdit event:
private void listView1_AfterLabelEdit(object sender, LabelEditEventArgs e)
{
yourLabel.Text = e.Label;
}
Don't forget to hook up the event!
If you want to display the new text while typing you can either try to listen to the keyboard between the BeforeLabelEdit and AfterLabelEdit events or you can overlay your own TextBox and use its TextChanged event.
I think this is easier but if you want to do special things, like disallowing editing key etc, it will alway mean some extra work!
Here is a short example how to overlay a TextBox over the Item:
TextBox EditCell = new TextBox();
public Form1()
{
InitializeComponent();
//..
EditCell.TextChanged += EditCell_TextChanged;
EditCell.Leave += EditCell_Leave;
EditCell.KeyDown += EditCell_KeyDown;
}
void EditCell_TextChanged(object sender, EventArgs e)
{
yourLabel.Text = EditCell.Text;
}
void EditCell_Leave(object sender, EventArgs e)
{
ListViewItem lvi = EditCell.Tag as ListViewItem;
if (lvi != null) lvi.Text = EditCell.Text;
EditCell.Hide();
}
void EditCell_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.Handled = true;
EditCell_Leave(null, null);
}
else if (e.KeyCode == Keys.Escape)
{
e.Handled = true;
EditCell.Tag = null;
EditCell_Leave(null, null);
}
e.Handled = false;
}
private void listView1_BeforeLabelEdit(object sender, LabelEditEventArgs e)
{
// stop editing the item!
e.CancelEdit = true;
ListViewItem lvi = listView1.Items[e.Item];
EditCell.Parent = listView1;
EditCell.Tag = lvi;
EditCell.Bounds = lvi.Bounds;
EditCell.BackColor = Color.WhiteSmoke; // suit your taste!
EditCell.Text = lvi.Text;
EditCell.Show();
EditCell.SelectionStart = 0;
EditCell.Focus();
EditCell.Multiline = true; // needed to allow enter key
}
The above code works fine but as our chat has established that you actually only want to grab keyboard input and direct it to a Label, here is the much, much simpler solution to the 'hidden' problem..:
Start by setting your Forms's KeyPreview totrue. Then hook up the KeyPressed event of the Form:
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (ActiveControl == listView1)
{
e.Handled = true; // needed to prevent an error beep
yourLabel.Text += e.KeyChar.ToString();
}
}
This will not allow any editing and only let the label text grow. You may want to expand with a few extras, like coding for Backspace, if you like..:
if (e.KeyChar == (char)Keys.Back && yourLabel.Text.Length > 0)
yourLabel.Text = yourLabel.Text.Substring(0, yourLabel.Text.Length - 1);
else yourLabel.Text += e.KeyChar.ToString();

How can I catch both single-click and double-click events on WPF FrameworkElement?

I can catch a single-click on a TextBlock like this:
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("you single-clicked");
}
I can catch a double-click on a TextBlock like this:
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (e.ClickCount == 2)
{
MessageBox.Show("you double-clicked");
}
}
}
But how do I catch them both on a single TextBlock and differentiate between the two?
You need to fire the event after the click sequence is over... when is that? I suggest using a timer. The MouseDown event would reset it and increase the click count. When timer interval elapses it makes the call to evaluate the click count.
private System.Timers.Timer ClickTimer;
private int ClickCounter;
public MyView()
{
ClickTimer = new Timer(300);
ClickTimer.Elapsed += new ElapsedEventHandler(EvaluateClicks);
InitializeComponent();
}
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
ClickTimer.Stop();
ClickCounter++;
ClickTimer.Start();
}
private void EvaluateClicks(object source, ElapsedEventArgs e)
{
ClickTimer.Stop();
// Evaluate ClickCounter here
ClickCounter = 0;
}
Cheers!
If you need to detect the difference, I suggest you use a control such as Label that does the work for you:
label.MouseDown += delegate(object sender, MouseEventArgs e)
{
if (e.ClickCount == 1)
{
// single click
}
};
label.MouseDoubleClick += delegate
{
// double click
};
EDIT: My advice was following from documentation on MSDN:
The Control class defines the
PreviewMouseDoubleClick and
MouseDoubleClick events, but not
corresponding single-click events. To
see if the user has clicked the
control once, handle the MouseDown
event (or one of its counterparts) and
check whether the ClickCount property
value is 1.
However, doing so will give you a single click notification even if the user single clicks.
You must use a timer to differentiate between the two. Add a timer to your form in the GUI (easiest that way - it will automatically handle disposing etc...). In my example, the timer is called clickTimer.
private bool mSingleClick;
private void TextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (e.ClickCount < 2)
{
mSingleClick = true;
clickTimer.Interval = System.Windows.Forms.SystemInformation.DoubleClickTime;
clickTimer.Start();
}
else if (e.ClickCount == 2)
{
clickTimer.Stop();
mSingleClick = false;
MessageBox.Show("you double-clicked");
}
}
}
private void clickTimer_Tick(object sender, EventArgs e)
{
if (mSingleClick)
{
clickTimer.Stop();
mSingleClick = false;
MessageBox.Show("you single-clicked");
}
}
I did it this Way and it works perfectly
If e.Clicks = 2 Then
doubleClickTimer.Stop()
ElseIf e.Clicks = 1 Then
doubleClickTimer.Enabled = True
doubleClickTimer.Interval = 1000
doubleClickTimer.Start()
End If
Private Sub doubleClickTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles doubleClickTimer.Tick
OpenWebPage("abc")
doubleClickTimer.Stop()
End Sub
You are simply can use MouseDown event and count click number, like this:
if (e.ChangedButton == MouseButton.Left && e.ClickCount == 2)
{
// your code here
}
My suggestion, implemented in a UserControl by simply using a Task:
private int _clickCount = 0;
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
_clickCount = e.ClickCount;
}
protected override async void OnPreviewMouseUp(MouseButtonEventArgs e)
{
if (_clickCount > 1)
{
//apparently a second mouse down event has fired => this must be the second mouse up event
//no need to start another task
//the first mouse up event will be handled after the task below
return;
}
await Task.Delay(500);
if (_clickCount == 1)
{
//single click
}
else
{
//double (or more) click
}
}
The drawback of all these solutions is, of course, that there will be a delay before actually responding to the user's action.
You could do it on MouseUp instead of MouseDown. That way you can ask the ClickCount property for the total number of clicks, and decide what to do from that point.
It's my working solution :)
#region message label click --------------------------------------------------------------------------
private Timer messageLabelClickTimer = null;
private void messageLabel_MouseUp(object sender, MouseButtonEventArgs e)
{
Debug.Print(e.ChangedButton.ToString() + " / Left:" + e.LeftButton.ToString() + " Right:" + e.RightButton.ToString() + " click: " + e.ClickCount.ToString());
// in MouseUp (e.ClickCount == 2) don't work!! Always 1 comes.
// in MouseDown is set e.ClickCount succesfully (but I don't know should I fire one clicked event or wait second click)
if (e.ChangedButton == MouseButton.Left)
{
if (messageLabelClickTimer == null)
{
messageLabelClickTimer = new Timer();
messageLabelClickTimer.Interval = 300;
messageLabelClickTimer.Elapsed += new ElapsedEventHandler(messageLabelClickTimer_Tick);
}
if (! messageLabelClickTimer.Enabled)
{ // Equal: (e.ClickCount == 1)
messageLabelClickTimer.Start();
}
else
{ // Equal: (e.ClickCount == 2)
messageLabelClickTimer.Stop();
var player = new SoundPlayer(ExtraResource.bip_3short); // Double clicked signal
player.Play();
}
}
}
private void messageLabelClickTimer_Tick(object sender, EventArgs e)
{ // single-clicked
messageLabelClickTimer.Stop();
var player = new SoundPlayer(ExtraResource.bip_1short); // Single clicked signal
player.Play();
}
#endregion
My issue was with single/double-clicking rows in a DataGrid in WPF. For some reason the ButtonDown events weren't firing, only the OnMouseLeftButtonUp event was. Anyway, I wanted to handle the single-click differently from the double-click. It looks me a little time (I'm sure the solution isn't perfect, but it appears to work) to distill the problem down until I got it down to the below. I created a Task which calls an Action and that Action's target can be updated by a second click. Hope this helps someone!
private Action _clickAction;
private int _clickCount;
private void Grid_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("Button Click Occurred");
_clickCount++;
if (_clickCount == 1)
{
_clickAction = SingleClick;
}
if (_clickCount > 1)
{
_clickAction = DoubleClick;
}
if (_clickCount == 1)
{
Task.Delay(200)
.ContinueWith(t => _clickAction(), TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => { _clickCount = 0; });
}
}
private void DoubleGridClick()
{
Debug.WriteLine("Double Click");
}
private void SingleGridClick()
{
Debug.WriteLine("Single Click");
}

Timer intervals, Making 1 timer stop another timer -

Hey guys im trying to get a simple button masher up, What i want timer1 to do is mash keys in richtextbox1 for 30 seconds over and over, after 30 seconds Activate timer2, which will disable timer 1 and press keys in richtextbox 2 once, then wait 10 seconds and activate timer 1 again.
Im extremley new to c# but ive tried using timer 3 to stop timer 2 and start timer 1 again and it just messes it self up. The code ive tried is below. Any help apreciated...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
SendKeys.Send(richTextBox1.Text);
SendKeys.Send("{ENTER}");
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
timer2.Enabled = true;
}
private void timer2_Tick(object sender, EventArgs e)
{
SendKeys.Send(richTextBox2.Text);
SendKeys.Send("{ENTER}");
timer1.Enabled = false;
}
private void timer3_Tick(object sender, EventArgs e)
{
timer1.Enabled = true;
timer2.Enabled = false;
}
private void richTextBox2_TextChanged(object sender, EventArgs e)
{
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
}
}
}
I suggest to use just one timer, increment a state counter every second, and perform an action base on the current state.
public Form1()
{
this.InitializeComponent();
// Just to illustrate - can be done in the designer.
this.timer.Interval = 1000; // One second.
this.timer.Enable = true;
}
private Int32 state = 0;
private void timer_Tick(Object sender, EventArgs e)
{
if ((0 <= this.state) && (this.state < 30)) // Hit text box 1 30 times.
{
SendKeys.Send(this.richTextBox1.Text);
SendKeys.Send("{ENTER}");
}
else if (this.state == 30) // Hit text box 2 once.
{
SendKeys.Send(this.richTextBox2.Text);
SendKeys.Send("{ENTER}");
}
else if ((31 <= this.state) && (this.state < 40)) // Do nothing 9 times.
{
// Do nothing.
}
else
{
throw new InvalidOperationException(); // Unexpected state.
}
// Update state.
this.state = (this.state + 1) % 40;
}
The variant with two numeric up down controls.
public Form1()
{
this.InitializeComponent();
// Just to illustrate - can be done in the designer.
this.timer.Interval = 1000; // One second.
this.timer.Enable = true;
}
private Int32 state = 0;
private void timer_Tick(Object sender, EventArgs e)
{
Decimal n1 = this.numericUpDown1.Value;
Decimal n2 = this.numericUpDown2.Value;
if ((0 <= this.state) && (this.state < n1))
{
SendKeys.Send(this.richTextBox1.Text);
SendKeys.Send("{ENTER}");
}
else if (this.state == n1)
{
SendKeys.Send(this.richTextBox2.Text);
SendKeys.Send("{ENTER}");
}
else if ((n1 <= this.state) && (this.state < n1 + n2))
{
// Do nothing.
}
else
{
// Reset state to resolve race conditions.
this.state = 0;
}
// Update state.
this.state = (this.state + 1) % (n1 + n2);
}
If timer3 is running continuously, won't it start timer1 and stop timer2 at unpredictable times, without warning?
IOW, what starts and stops timer3?
As JustLoren pointed out, there might be a cleaner way to do this. Perhaps a single timer event and some controlling logic and flags, rather than trying to juggle three timers.

Categories

Resources