private void button1_Click_1(object sender, EventArgs e)
{
lbl_startingTest.Text = "Flashing DUT..";
Process fls1 = new Process();
fls1.StartInfo.UseShellExecute = false;
//fls1.StartInfo.RedirectStandardOutput = true;
fls1.StartInfo.FileName = "C:\\test\\test\\bin\\Debug\\flash.bat";
fls1.StartInfo.CreateNoWindow = true;
fls1.Start();
//
fls1.WaitForExit();
}
Tried different methods, but no result achieved. Please suggest. I am trying to update the label "Flashing DUT..." to "Flashing Complete" when fls1 process completes execution.
fsl1 process is a Batch file named flash.bat
Related
I have a WPF application where I am running a powershell script that returns a sequence of strings. I want to be able to update my UI asynchronously, but the UI will only update once the method is complete. How do I update the UI asynchronously? I have been reading a lot of other similar examples like this one: WPF User Control children not updating c# Maybe this works, but I could be implementing it incorrectly?
My code:
private void NextButton_Click(object sender, RoutedEventArgs e)
{
RunPreCheck();
}
public void RunPreCheck()
{
var startInfo = GetPowerShellStartInfo();
proc = Process.Start(startInfo);
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
var myObject= new MyCustomObject(line);
myGrid.Children.Add(myObject);
}
}
Run RunPreCheck() on a background thread:
private void NextButton_Click(object sender, RoutedEventArgs e)
{
Task.Run(RunPreCheck);
}
public void RunPreCheck()
{
var startInfo = GetPowerShellStartInfo();
proc = Process.Start(startInfo);
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
myGrid.Dispatcher.BeginInvoke(
new Action(() => myGrid.Children.Add(new MyCustomObject(line))));
}
}
I'm trying to save a rather large text file when the user hits the save button. It can be up to 30MBs. After pressing the button, I'd like the texbox to display "Saving..." as it's saving the file and when it completes, display "Saved". However I can't get this to work. I've tried using Task.run, await task.Run, and using a background worker. All these options hang the UI until the save completes. The textbox does not display "Saving..." until after it saves and the program is unresponsive until then. How can I fix this?
private async void btnSave_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.ShowDialog();
// If the file name is not an empty string open it for saving.
if (saveFileDialog1.FileName != "")
{
logFileName = saveFileDialog1.FileName;
btnOpenFile.IsEnabled = false;
btnSave.IsEnabled = false;
tbText1.Text += "\n\n***Saving...***\n";
tbText1.ScrollToEnd();
await Task.Run(() => File.WriteAllText(logFileName, Results.ToString()));
tbText1.Text += "\n\n***SAVED***\n\n";
tbText1.ScrollToEnd();
btnOpenFile.IsEnabled = true;
btnSave.IsEnabled = true;
}
As discussed in the comments, the problem is with Results.ToString().
I tried to reproduce the issue with this code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
for (int i = 1; i < 40536; i++)
{
stringBuilder.Append(new string('a', i));
}
}
readonly StringBuilder stringBuilder = new StringBuilder();
int tickNumber = 0;
private void sync_Click(object sender, EventArgs e)
{
button1.Enabled = false;
stringBuilder.ToString();
button1.Enabled = true;
}
private async void async_Click(object sender, EventArgs e)
{
button2.Enabled = false;
await Task.Run(() => stringBuilder.ToString());
button2.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
tickNumber %= 50;
tickNumber++;
label1.Text = new string('.', tickNumber);
}
}
But it works as expected:
Sometimes UI hands for a little bit though. Is this what are you talking about?
Try moving code that generates contents for StringBuilder inside the task (so this StringBuilder only exists in background thread)
I've created a new WinForms project in Visual Studio 2017.
Then I've added a button and textbox to Form1 (screenshot).
Code:
using System;
using System.Net;
using System.Windows.Forms;
namespace TestWinForms
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void FormDelegate();
private void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
BeginInvoke(new FormDelegate(delegate
{
using (WebClient web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
textBox1.Text = web.DownloadString("https://stackoverflow.com/");
}
UseWaitCursor = false;
button1.Enabled = true;
}));
}
}
}
When I click button1 window cursor isn't changing to WaitCursor, and when I hover cursor over ControlBox buttons they aren't "glowing". In short, BeginInvoke() blocks main thread for a moment. Why this is happening and how can I avoid it?
As the fellow users said in the comments, it's DownloadString that's blocking your UI, not BeginInvoke since it waits for the download to complete.
You should probably tackle this in another way, by using DownloadStringAsync:
private WebClient _web;
private void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
_web = new WebClient();
_web.Encoding = System.Text.Encoding.UTF8;
_web.DownloadStringCompleted += DownloadCompleted;
_web.DownloadStringAsync("https://stackoverflow.com/");
}
private void DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
textBox1.Text = e.Result;
UseWaitCursor = false;
button1.Enabled = true;
_web.Dispose();
}
I second Hans comment : the BeginInvoke only defer execution later.
What you need is either a BackgroundWorker or (better) using the async/await pattern:
private async void button1_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
button1.Enabled = false;
using (WebClient web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
textBox1.Text = await web.DownloadStringTaskAsync("https://stackoverflow.com/");
}
UseWaitCursor = false;
button1.Enabled = true;
};
}
The DownloadStringTaskAsync will run on a worker process because it is awaitable. While it runs, the UI thread will continue to process the other events anyway, then continue its execution after the await statement as the DownloadStringTaskAsync finishes.
My form contain two controls: button1 and timer1
timer1.Interval=1000; timer1.Enable=true;
While click button1, application on windows will start. Ex:notepad will show.
But timer1 is not running while notepad is showing.
How to timer1 so running ??.
My code:
private void button1_Click(object sender, EventArgs e)
{
Process pro = new Process();
pro.StartInfo.FileName = "notepad";
pro.StartInfo.Arguments = "";
pro.Start();
pro.WaitForExit();
}
private void timer1_Tick(object sender, EventArgs e)
{
DateTime dtime = DateTime.Now;
string date_time = dtime.ToString("dd/MM/yyyy HH:mm:ss");
textBox2.Text = date_time;
}
From Process.WaitForExit:
Instructs the Process component to wait indefinitely for the associated process to exit.
Your timer is trying to invoke timer1_Tick, but your UI Thread is currently stuck waiting for the process to exit, which it wont.
You have two choices to work around this:
Simply remove the call to WaitForExit if you dont really need to wait
If you do need to be notified when the process exits, set Process.EnableRaisingEvents to true and register to the Process.Exited event
The WaitForExit() is "blocking" your interface from refreshing,the call just waits there for the process to exit. As an alternative if you need to do something when the process as exited do this:
private void button1_Click(object sender, EventArgs e)
{
Process pro = new Process();
pro.StartInfo.FileName = "notepad";
pro.StartInfo.Arguments = "";
//if you need to do something when the process exits do this:
pro.EnableRaisingEvents = true;
pro.Exited += new EventHandler(pro_Exited);
pro.Start();
//pro.WaitForExit();
}
void pro_Exited(object sender, EventArgs e)
{
//do what you need here...
}
Instead you could start the process with a BackGroundWorker.
pro.WaitForExit(); makes UI thread to freeze so it can't update.
To stop user from actions, you can disable some controls, while process is running. You can subscribe to process.Exited event and enable your controls, when user closes the process.
private void button1_Click(object sender, EventArgs e)
{
Process pro = new Process();
pro.StartInfo.FileName = "notepad";
pro.StartInfo.Arguments = "";
pro.Start();
button1.Enabled = false;
pro.EnableRaisingEvents = true;
pro.Exited += pro_Exited;
}
void pro_Exited(object sender, EventArgs e)
{
button1.Invoke((MethodInvoker) delegate { button1.Enabled = true; });
}
Update
As another answer suggested you should set EnableRaisingEvents property to true.
Also pro_Exited method will run in a different thread, so you need to use Control.Invoke method to change UI.
Update 2
If can't delete pro.WaitForExit(); you can use another timer, because System.Windows.Forms.Timer is running in UI thread and is blocked with it.
private System.Threading.Timer timer = new System.Threading.Timer(Callback);
public Form()
{
InitializeComponent();
timer.Change(0, 1000);
}
private void Callback(object state)
{
DateTime dtime = DateTime.Now;
string date_time = dtime.ToString("dd/MM/yyyy HH:mm:ss");
button1.Invoke((MethodInvoker)delegate { textBox1.Text = date_time; });
}
It will not update the textBox, when process is opened, but the timer will run and can do some work.
Update 3
In case of multiple processes you can count them and check number of active processes in pro_Exited method.
private volatile int activeProcessCount = 0;
private void pro_Exited(object sender, EventArgs e)
{
activeProcessCount--;
if (activeProcessCount == 0)
{
button1.Invoke((MethodInvoker) delegate { button1.Enabled = true; });
}
}
private void button1_Click(object sender, EventArgs e)
{
//code
activeProcessCount = 2;
pro1.Start();
pro2.Start();
}
I have windows application in which i need to save data into database and after saving data load crystal report to show report,all this happens on click of save button.
I have button named btn_Submit on click of this data is saved and display report, while saving it takes time so i want to show progress bar for mean time so that user get known that data is in process.how i can do with this windows application.
I gone through this link http://www.codeproject.com/Tips/83317/BackgroundWorker-and-ProgressBar-demo but don't get it exactly I want.
I am aware of background worker but never used it.
I have used background worker and progress bar as given in above link but progress bar does not stop at all once it started.
Can any one help me?can u give any example or link that demonstrate scenario?.
This code i added on Dowork();
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
PrintData arg = (PrintData)e.Argument;
SalesMaster sm = arg.SalesData;
BrokerMaster bm = arg.Broker;
CustomerMaster ctm = arg.Customer;
CompanyMaster cm = arg.Company;
ArrayList hb = arg.Arrardata;
int totunit = arg.totunit;
decimal globalamt = arg.golbamt;
SalesReport sreport = new SalesReport(sm, ctm, cm, bm, hb, totunit, glb_totalamt);
sreport .MdiParent = arg.parentf;
sreport .WindowState = FormWindowState.Maximized;
sreport .Show();
}
i get error on this line sreport .MdiParent = arg.parentf;
This error:
Cross-thread operation not valid: Control 'frmParent' accessed from a thread other than the thread it was created on.
what should be done here?
Suscribe to DoWork and RunWorkerCompleted events and
void btn_Submit_Click(object sender, EventArgs e)
{
btn_Submit.Enabled = false; // disable button while saving report
lbl_Status.Text = "Please wait..";
backgroundWorker.RunWorkerAsync();
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// save report here
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btn_Submit.Enabled = true; // enable button
lbl_Status.Text = "Report saved";
}
Instead of using label, you can show PictureBox with spinner wait image. I don't like to see progress bar, which does not show percentage of task - I expect that when progress bar will be filled, task will be completed. If you really want to use progress bar, then, I'd go with timer component (set timer's interval to desired refresh rate):
void btn_Submit_Click(object sender, EventArgs e)
{
btn_Submit.Enabled = false; // disable button while saving report
timer.Start();
progressBar.Visible = true;
// backgroundWorker.RunWorkerAsync(new object[] { "Foo", 42 });
// backgroundWorker.RunWorkerAsync(new CustomType("Foo", 42));
backgroundWorker.RunWorkerAsync(new { Foo = "Foo", Bar = 42 }););
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// object[] args = (object[])e.Argument;
// CustomType arg = (CustomType)e.Argument;
dynamic arg = (dynamic)e.Argument;
string foo = arg.Foo;
int bar = arg.Bar;
// save report here
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btn_Submit.Enabled = true; // enable button
timer.Stop();
progressBar.Visible = false;
}
void timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value == progressBar.Maximum)
{
progressBar.Value = progressBar.Minimum;
return;
}
progressBar.PerformStep();
}
Try to reset the ProgressBar's Value property to 0, like in the code below:
Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
Implemented event handler:
void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Value = 0;
}
To stop or hide the progressbar use background worker's completed event.