c# Forms Timer does not stop - c#

I have a WinForms app that increments a timer once per second and updates a labels' text.
A second timer increments once every 20msec to look for recent mouse movements and writes the current coordinates to another label.
When the program receives Alt+F4 I instantiate "MessageBoxQueryClose" where the user is asked to close or resume operation. Before the MessageBox is displayed I'd like to stop
the once-per-second timer from firing, and after the user said "please continue" to re-enable it.
This is where I observed some 'strange' behavior: the once-per-second timer fires again
while the MessageBox is open and the mouse is moved.
Code for the form:
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;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Globalization;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private bool _altF4Pressed = false;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Alt && e.KeyCode == Keys.F4)
_altF4Pressed = true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// show the MessageBox asking the user if the programm should really exit
MessageBoxQueryClose msgBoxQC = new MessageBoxQueryClose();
msgBoxQC.QueryClose(ref _altF4Pressed, ref timer2, ref e);
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 20;
timer1.Enabled = true;
timer2.Interval = 1000;
timer2.Enabled = true;
}
bool toggle = false;
private void timer2_Tick(object sender, EventArgs e)
{
if (toggle)
label1.Text = "tick";
else
label1.Text = "tack";
toggle = !toggle;
}
Point oldPos, newPos;
private void timer1_Tick(object sender, EventArgs e)
{
newPos = Cursor.Position;
label2.Text = Convert.ToString(newPos.X + ", " + newPos.Y);
CompareCursorPosition();
oldPos = newPos;
}
private void CompareCursorPosition()
{
if (oldPos != newPos)
Display_ResetFallback();
}
private void Display_ResetFallback()
{
timer2.Stop();
timer2.Start();
}
}
}
Code for MessageBoxQueryClose:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
class MessageBoxQueryClose
{
public void QueryClose(ref bool _altF4Pressed, ref Timer timer, ref FormClosingEventArgs e)
{
if (_altF4Pressed)
{
// first, disable timer2 to stop Form1.label1 from being updated
timer.Enabled = false;
if (e.CloseReason == CloseReason.UserClosing)
{
DialogResult res;
res = MessageBox.Show("Close program ?", "timers",
MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
if (res == DialogResult.Yes)
{
return;
}
// if program execution shall continue, re-enable timer2
timer.Enabled = true;
}
e.Cancel = true;
_altF4Pressed = false;
}
}
}
}
I have the gut feeling that my issue is about timers and threading, but I only recently started out with .Net, so any insight is appreciated.
br, Chris

Your timer1_Tick event calls CompareCursorPosition(), which calls Display_ResetFallback(), which starts timer2 again.
So you stop timer2 in QueryClose(), but then the timer1_Tick event fires, starting timer2 up again.
You could modify Display_ResetFallback() to make sure your timer is only restarted if it's currently running:
if (timer2.Enabled)
{
timer2.Stop();
timer2.Start();
}
As a side note, I'd probably get rid of the MessageBoxQueryClose class entirely and just modify your FormClosing event accordingly:
if (e.CloseReason == CloseReason.UserClosing)
{
timer2.Stop();
if (MessageBox.Show("Close program ?", "timers", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
{
e.Cancel = true;
timer2.Start();
}
}

You can try this...
timer1.Stop();
label1.Text = timer1.Enabled == false ?"timer disabled":"timer enabled";
if (MessageBox.Show("Close program ?", "timers",
MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.OK)
{
//do stuff here if you want
}
timer1.Start();
label1.Text = timer1.Enabled == false ? "timer disabled" : "timer enabled";
just put those label text for you to check.
this edit you dont require the class
EDIT:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private bool _altF4Pressed = false;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Alt && e.KeyCode == Keys.F4)
_altF4Pressed = true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//show the MessageBox asking the user if the programm should really exit
//MessageBoxQueryClose msgBoxQC = new MessageBoxQueryClose();
//msgBoxQC.QueryClose(ref _altF4Pressed, ref timer2, ref e);
if (_altF4Pressed)
{
this.timer2.Stop();
if (MessageBox.Show("Close program ?", "timers",
MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
{
e.Cancel = true;
this.timer2.Start();
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 20;
timer1.Enabled = true;
timer2.Interval = 1000;
timer2.Enabled = true;
}
bool toggle = false;
private void timer2_Tick(object sender, EventArgs e)
{
if (toggle)
label1.Text = "tick";
else
label1.Text = "tack";
toggle = !toggle;
}
//Point oldPos, newPos;
private void timer1_Tick(object sender, EventArgs e)
{
label2.Text = MousePosition.X.ToString() + " , " + MousePosition.Y.ToString();
}
//private void CompareCursorPosition()
//{
// if (oldPos != newPos)
// Display_ResetFallback();
//}
//private void Display_ResetFallback()
//{
// timer2.Stop();
// timer2.Start();
//}
}
Just put my first post inside your code....It stops for me,and no need for the extra class,removed the 2 points and the 2 methods(Display_ResetFallback and CompareCursorPosition),but you can use them(the 2 point variables) if you want and inside timer1 do your checks.

Related

Loop Script not updating other forms

Long Story Short,
The app I am making will Launch a Game.
The Start button will then Check to make sure the games EXE is running..
IF it is running, it will run a script to press buttons 1, 2, and 3..
After that it will loop that script, but first checking if the game has not crashed (if it crashed it wont run the loop)
My Issue:
While the loop is running, which is using System.Threading.Thread.Sleep,
does not let other functions of the app preform (in this case showing and hiding button, and changing label colors.) The main reason this is important is the button it wont is the Stop button which is suppose to end the looping script.
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
Timer timer;
Stopwatch sw;
public Form1()
{
InitializeComponent();
button4.Visible = false;
button2.Enabled = false;
}
private void timer_Tick(object sender, EventArgs e)
{
label2.Text = sw.Elapsed.Seconds.ToString() + "seconds";
Application.DoEvents();
}
// ===============================================
// BUTTON FUNCTIONS
// ===============================================
// Launch GAME
private void button1_Click(object sender, EventArgs e)
{
// Launch GAME
Process.Start(#"C:\Windows\System32\Notepad.exe");
button2.Enabled = true;
}
// START BOT
private void button2_Click(object sender, EventArgs e)
{
status.Text = #"Starting Bot..";
timer = new Timer();
timer.Interval = (1000);
timer.Tick += new EventHandler(timer_Tick);
sw = new Stopwatch();
timer.Start();
sw.Start();
BotReady(sender, e);
}
// PLAYER DIED
private void button3_Click(object sender, EventArgs e)
{
KillBot(sender, e);
status.Text = #"lol u ded";
}
// STOP THE BOT
private void button4_Click(object sender, EventArgs e)
{
KillBot(sender, e);
status.Text = #"Bot Stopped";
button2.Visible = true;
button4.Visible = false;
button2.Enabled = true;
}
// KILL GAME AND BOT (IF IT CRASHED OR SOMETHING)
private void button5_Click(object sender, EventArgs e)
{
}
// ===============================================
// OTHER FUNCTIONS
// ===============================================
// Target GAME application
private void TargetAQ(object sender, EventArgs e)
{
// this part doesnt work yet.
// Selection.Application and Tab to it
}
// CHECK IF GAME IS STILL RUNNING, KILL BOT IF GAME IS NOT DETECTED
public void CheckStatus(object sender, EventArgs e)
{
Process[] GAME = Process.GetProcessesByName("notepad");
if (GAME.Length == 0)
// GAME NOT running
{
KillBot(sender, e);
button2.Enabled = false;
status.Text = #"GAME is not Running, Bot Stopped.";
uGAME.ForeColor = Color.Red;
button2.Visible = true;
button4.Visible = false;
button2.Enabled = false;
}
else
// GAME IS running
{
status.Text = #"GAME is Running!";
uGAME.ForeColor = Color.Green;
button2.Visible = false;
button4.Visible = true;
}
}
// Verify bot and GAME are running before starting
public void BotReady(object sender, EventArgs e)
{
CheckStatus(sender, e);
if (uGAME.ForeColor == Color.Green)
{
status.Text = #"Bot Started!";
Botting(sender, e);
}
else { status.Text = #"GAME is not running"; }
}
//THE BOT ACTIONS
public void Botting(object sender, EventArgs e)
{
// Check to make sure everything is still running
CheckStatus(sender, e);
TargetAQ(sender, e);
if (uGAME.ForeColor == Color.Green)
{
// all is running, then you good.
Script(sender, e);
}
//GAME died, kill scripts
else {
KillBot(sender, e);
status.Text = #"GAME Crashed:(";
}
}
//Things it does in-game
public void Script(object sender, EventArgs e)
{
status.Text = #"Bot in progress..";
// Use skills in game rotation
System.Threading.Thread.Sleep(3000);
SendKeys.Send("1");
System.Threading.Thread.Sleep(3000);
SendKeys.Send("2");
System.Threading.Thread.Sleep(3000);
SendKeys.Send("3");
// Go back and check the game has not crashed before re-running the script
Botting(sender, e);
}
// STOP THE BOT AND TIME COUNTER
public void KillBot(object sender, EventArgs e)
{
// kill the clock and bot
status.Text = #"Stopping bot...";
timer.Stop();
sw.Stop();
label2.Text = sw.Elapsed.Seconds.ToString() + " seconds";
status.Text = #"Bot Stopped";
}
}
}

save data to .txt file at the same time click "read" button

i want to save received data to .txt file when click "read" button. please help me
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;
using System.Threading;
using System.IO.Ports;
namespace Serial
{
public partial class Form1 : Form
{
static SerialPort serialPort1;
public Form1()
{
InitializeComponent();
getAvailablePorts();
serialPort1 = new SerialPort();
}
void getAvailablePorts()
{
string[] Ports = SerialPort.GetPortNames();
comboBox1.Items.AddRange(Ports);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button3_Click(object sender, EventArgs e)
{
try
{
if (comboBox1.Text == "" || comboBox2.Text == "")
{
textBox2.Text = "Please select port Setting";
}
else
{
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
serialPort1.Open();
progressBar1.Value = 100;
button1.Enabled = true;
button2.Enabled = true;
textBox1.Enabled = true;
button3.Enabled = false;
button4.Enabled = true;
}
}
catch (UnauthorizedAccessException)
{
textBox2.Text = "anauthorized Acess";
}
}
private void button4_Click(object sender, EventArgs e)
{
serialPort1.Close();
progressBar1.Value = 0;
button1.Enabled = false;
button2.Enabled = false;
button4.Enabled = false;
button3.Enabled = true;
textBox1.Enabled = false;
}
private void button1_Click(object sender, EventArgs e)
{
serialPort1.WriteLine(textBox1.Text);
textBox1.Text = "";
}
private void button2_Click(object sender, EventArgs e)
{
try
{
textBox2.Text = serialPort1.ReadLine();
}
catch(TimeoutException)
{
textBox2.Text = "Timeout Exception";
}
}
}
}
Simply use File.WriteAllText.Sample :
File.WriteAllText("path here","text here")
Just use StreamWriter
using(StreamWriter sw = new StreamWriter("filename.txt")){
sw.WriteLine(textbox.Text);
sw.Close();
}

How can I show correctly a progressbar and a label (that show the percentage) for filling multiple datasets?

I need to update a DataGridView that has master detail part, I'm trying to use this control for the grid (I use 4 datasets for filling the grid).
Question: how can I add correctly a thread or more that will add to the grid these datasets and show the correct percentage and the same time the UI remain usable(responsive, not to become "not responding" for user)?
In every table I have about 10000 rows.
Please provide some code if possible, because I'm stuck.
Thanks in advance,
Steve
I tried like this, but I'm stuck at showing the user the correct percentage and correctly using the thread:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace MasterDetail
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
MasterControl masterDetail;
private void frmMain_Load(object sender, EventArgs e)
{
//label1.Text = DateTime.Now.ToString();
clearFields();
loadData();
//label2.Text = DateTime.Now.ToString();
}
void clearFields()
{
panelView.Controls.Clear();
masterDetail = null;
Refresh();
masterDetail = new MasterControl(nwindDataSet);
panelView.Controls.Add(masterDetail);
}
internal delegate void SetDataSourceDelegate();
private void setDataSource()
{
if (this.masterDetail.InvokeRequired)
{
this.masterDetail.BeginInvoke(new SetDataSourceDelegate(setDataSource));
}
else
{
createMasterDetailView();
}
}
void loadData()
{
System.Threading.Thread thread =
new System.Threading.Thread(new System.Threading.ThreadStart(delegate() { loadDataThread(); }));
thread.Start();
}
void loadDataThread()
{
orderReportsTableAdapter.Fill(nwindDataSet.OrderReports);
invoicesTableAdapter.Fill(nwindDataSet.Invoices);
employeesTableAdapter.Fill(nwindDataSet.Employees);
customersTableAdapter.Fill(nwindDataSet.Customers);
setDataSource();
}
void createMasterDetailView()
{
masterDetail.setParentSource(nwindDataSet.Customers.TableName, "CustomerID");
masterDetail.childView.Add(nwindDataSet.OrderReports.TableName, "Orders");
masterDetail.childView.Add(nwindDataSet.Invoices.TableName, "Invoices");
masterDetail.childView.Add(nwindDataSet.Employees.TableName, "Employees");
typeof(DataGridView).InvokeMember("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty, null,
masterDetail, new object[] { true });
foreach (DataGridView dvg in masterDetail.childView.childGrid)
{
typeof(DataGridView).InvokeMember("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty, null,
dvg, new object[] { true });
}
masterDetail.childView.childGrid[2].RowTemplate.Height = 100;
}
private void btnLoad_Click_1(object sender, EventArgs e)
{
Application.Exit();
}
}
}
I think it would be better for you to use a backgroundworker
It has an event called WorkerReportsProgress that can help you create the progressbar you need.
Here is the sample code from msdn:
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void startAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
backgroundWorker1.CancelAsync();
}
}
// This event handler is where the time-consuming work is done.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
// This event handler updates the progress.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
resultLabel.Text = (e.ProgressPercentage.ToString() + "%");
}
// This event handler deals with the results of the background operation.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
you just need to add the proper computation of the percentage and you're done

C# SERIAL PORT TEXTBOX ISSUE

I want to create a form having button,textbox,serialport in Visual c# 2010. My objective is when a button is pressed the data coming from the serial port has to displayed in textbox. I copied the following code from a tutorial. The textbox is not showing anything. Here's is the code
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 ser1
{
public partial class Form1 : Form
{
private string RxString;
public Form1()
{
InitializeComponent();
}
private void buttonStart_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM4";
serialPort1.BaudRate = 9600;
serialPort1.Open();
if (serialPort1.IsOpen)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
textBox1.ReadOnly = false;
}
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
// If the port is closed, don't try to send a character.
if (!serialPort1.IsOpen) return;
// If the port is Open, declare a char[] array with one element.
char[] buff = new char[1];
// Load element 0 with the key character.
buff[0] = e.KeyChar;
// Send the one character buffer.
serialPort1.Write(buff, 0, 1);
// Set the KeyPress event as handled so the character won't
// display locally. If you want it to display, omit the next line.
e.Handled = true;
}
private void DisplayText(object sender, EventArgs e)
{
textBox1.Text=RxString.Trim();
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
RxString = serialPort1.ReadExisting();
this.Invoke(new EventHandler(DisplayText));
}
private void buttonStop_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
textBox1.ReadOnly = true;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (serialPort1.IsOpen) serialPort1.Close();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
}'

C# Minimize to system tray on close

Hi In my c# application I am trying to minimize application to systems tray, when the form is closed. Here is the code I have tried.
public void MinimizeToTray()
{
try
{
notifyIcon1.BalloonTipTitle = "Sample text";
notifyIcon1.BalloonTipText = "Form is minimized";
if (FormWindowState.Minimized == this.WindowState)
{
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(500);
this.Hide();
}
else if (FormWindowState.Normal == this.WindowState)
{
notifyIcon1.Visible = false;
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and I am calling the method to form closing event. But the problem is its not minimizing to tray. Its just closing the form.
e.Cancel = true; code will be always cancelling the event even if you shut the computer down, but here is a code that helps you:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
myNotifyIcon.Visible = true;
this.Hide();
e.Cancel = true;
}
}
It will allow closing the form programmaticaly.
Write a event in Form Closing event.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
And write using Custom menu strip for notification icon for to show.
namespace MinimizeTrayNotification
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void MinimzedTray()
{
notifyIcon1.Visible = true;
notifyIcon1.Icon = SystemIcons.Application;
notifyIcon1.BalloonTipText = "Minimized";
notifyIcon1.BalloonTipTitle = "Your Application is Running in BackGround";
notifyIcon1.ShowBalloonTip(500);
}
private void MaxmizedFromTray()
{
notifyIcon1.Visible = true;
notifyIcon1.BalloonTipText = "Maximized";
notifyIcon1.BalloonTipTitle = "Application is Running in Foreground";
notifyIcon1.ShowBalloonTip(500);
}
private void Form1_Resize(object sender, EventArgs e)
{
if(FormWindowState.Minimized==this.WindowState)
{
MinimzedTray();
}
else if (FormWindowState.Normal == this.WindowState)
{
MaxmizedFromTray();
}
}
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.WindowState = FormWindowState.Normal;
Form1 frm = new Form1();
frm.Show();
MaxmizedFromTray();
}
private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
{
this.WindowState = FormWindowState.Normal;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
this.Hide();
}
}
private void notifyIcon1_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Normal;
notifyIcon1.BalloonTipText = "Normal";
notifyIcon1.ShowBalloonTip(500);
}
}
}
You should cancel the FormClosing event and then call your MinimizeToTray() function.
This is done through the Cancel property of the FormClosingEventArgs.
Also, consider using a bool somewhere to allow closing the Form in some conditions, such as if you're using a File > Exit menu or something:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(!allowClosing)
{
e.Cancel = true;
MinimizeToTray();
}
}
To minimize when closing set WindowState to Minimized
private void Form1_FormClosing(Object sender, FormClosingEventArgs e) {
e.Cancel = true;
WindowState = FormWindowState.Minimized;
}
You need to use the FormClosing-Event.
private void Form1_FormClosing(Object sender, FormClosingEventArgs e) {
e.Cancel = true;
MinimizeToTray();
}
You can handle FormClosing Event such as micsoft Form Closing Event as Following example of C#
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Determine if text has changed in the textbox by comparing to original text.
if (textBox1.Text != strMyOriginalText)
{
// Display a MsgBox asking the user to save changes or abort.
if (MessageBox.Show("Do you want to save changes to your text?", "My Application",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
// Cancel the Closing event from closing the form.
e.Cancel = true;
// Call method to save file...
}
}
}

Categories

Resources