I have been supplied an executable that communicates with boards under test using USB. The supplied exe is then called in a polling loop from my application using Process
to run cmd.exe. My application is a C# WPF app. I am new to Tasks but have gone through many variations to get what I think is the correct way of using Task
to run the Process
in a separate Task
thread. The problem is when Process
code is running my UI flashes during Process
call, and I can't move the UI for example. Also if trying to use another application, such as Word, anything I'm doing will be interrupted by my application when Process
is running.
I've tried a lot of things but where I am right now is I'm using the below code for the Process
. The polling loop is started with a button press. All methods that call the Process code are using the public async Task Method(parameters)
format, except the button code which is format
private async void Execute(object parameter)
.
Process
class code extract:
List<string> TestResults = new List<string>();
private Process process;
private TaskCompletionSource<bool> eventHandled;
public async Task<List<string>> GetData(string cmdString)
{
process = new Process();
eventHandled = new TaskCompletionSource<bool>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
TestResults.Clear();
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.WorkingDirectory = WorkingDirectoryPath;
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(ExitedProcess);
process.OutputDataReceived += OutputDataHandler;
// process.ErrorDataReceived += ErrorDataHandler;
process.StartInfo.FileName = CommandExe;
if (cmdString != null)
{
process.StartInfo.Arguments = cmdString;
}
else
{
return null;
}
process.Start();
process.BeginOutputReadLine();
// process.BeginErrorReadLine();
// process.WaitForExit(); // comment out if using Task
await Task.WhenAll(eventHandled.Task, Task.Delay(100));
process.Dispose();
stopwatch.Stop();
FmpViewModel.Notes.Add($"Call Ended: {stopwatch.ElapsedMilliseconds}ms");
return TestResults;
}
private void ExitedProcess(object sender, System.EventArgs e)
{
eventHandled.TrySetResult(true);
}
private void OutputDataHandler(object sendingProcess,
DataReceivedEventArgs data)
{
if (!string.IsNullOrEmpty(data.Data))
{
TestResults.Add(data.Data);
}
}
The Execute
method:
private async void Execute(object parameter)
{
tokenSource = new CancellationTokenSource();
token = tokenSource.Token;
//Turn on Cancel button
CanExecuteEnable = false;
//Turn off Initialize button
CanInitEnable = false;
await ExecuteTest(token);
}
EDIT 2: I finally found the problem is caused by the change in focus when Process()
runs. The problem is described by nawfal here
How to set focus back to form after opening up a process (Notepad)? and he offers a solution that worked for him. In my case adding the Topmost="True" to XAML was the best solution for my situation.
EDIT: I found this post A Tour of Task, Part 9: Delegate Tasks mainly about Task.Run
section. So I changed my code to wrap all the calls to the Process()
code in a Task.Run
to see if it does use separate threads and it does example below. But I still have the same problem, this did not fix it. I did add a Topmost="True"
to the xaml to keep the application window on top and that stopped the flicker on the test app. But if I have other apps open they still have the interference like the focus keeps shifting away whenever the Process()
calls occur.
UI Thread 1
Thread Task.Run() 9
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 9
Thread during Task.WhenAny() 9
Thread during Task.WhenAny() 9
Thread during Task.WhenAny() 9
Thread during Task.WhenAny() 9
Thread during Task.WhenAny() 9
Thread during Task.WhenAny() 9
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 11
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 13
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
Thread during Task.WhenAny() 7
UI Thread after Task.Run() 1