GUI update from another thread - WPF Powershell - wpf

I asked this question before, but I still am having issues. Really hoping I could have some assistance. all I need is to be able to add append text to my Rich TextBox from a background job. If I remove Start-Job -ScriptBlock { } it updates fine while on the GUI thread. What can I do in order to update my richtextbox from Start-Job?
Start-Job -ScriptBlock{
$richTextBox1.AppendText('++++++++++++++++')
$richTextBox1.Dispatcher.Invoke([action]{
$richTextBox1.AppendText('-------------')
},"Normal")
}

I'm not a massive user of Powershell within WPF however as I understand your post I think I can still help.
public void RunPowershell_Script()
{
Thread t = new Thread(new ThreadStart(
delegate
{
Start-Job -ScriptBlock{
this.Dispatcher.Invoke((Action)(() =>
{
//Any Element that you need to interact with variables
//or controls from the main application on the main
//dispatcher thread go here.
$richTextBox1.AppendText('++++++++++++++++')
$richTextBox1.AppendText('-------------')
}));
}
//Any final code can go here.
}
));
t.Start();
}
I believe this should work but you would have to have a play around. the above is the best way to access the main dispatcher thread in which the RTF box was originally created. Give it a try and let me know if it still doesn't work.

Related

Check if form is Opened Winform / Powershell

I'm searching how I could check if a winform form is opened with Powershell, like this response for VB.net. I'm working with two runspaces, and I need to start the second, when my form is opened.
My first runspace is for the GUI. When the UI creation is completed, I opened it
$CommonHashTable.MainForm.ShowDialog()
And then, I'm trying to test if this form is opened (snipet from VB.net) from PowerShell main thread:
If Application.OpenForms().OfType(Of $CommonHashTable.MainForm).Any Then
... startsecondrunspace
A better way to test if the form is open might be to
if ($CommonHashTable.MainForm.IsHandleCreated) {
startsecondrunspace
}
Application.OpenForms() would be a method on an Application Class rather than the Form class. I am unsure if there is an instance of the Application class to even be able to use that method. If there was, I would imagine it should look something like this:
If ($ApplicationObject.OpenForms().OfType(Of $CommonHashTable.MainForm).Any) {
startsecondrunspace
}
Thanks you very much, I have created this function :
do {
RecordToLog -Message "Waiting..."
start-sleep -m 100
} until ($CommonHashTable.MainForm.IsHandleCreated)
startsecondrunspace
It's working.

Show window with progressbar while doing work

Because I have a tool that needs to do a lot of work at one point, I want to show a window with some text and a progressbar while doing the work.
My problem is, that because of the huge load of the work, the window never gets drawn or updated.
I know that I usually should use an extra thread for the work, but I have to use 2 collections and the database service from the current thread.
The current code is something like
StatusWindow SW = new StatusWindow();
StatusViewModel SVM = new StatusViewModel();
SVM.MaxNum = BigNumber;
SW.Show();
for (int i=0; i<BigNumber; i++)
{
List<AType> ItemsToCreate = Func1();
List<AType> ItemsToDelete = Func2();
foreach (AType cItem in ItemsToCreate)
DB.CreateItem(cItem);
foreach (AType cItem in ItemsToDelete)
DB:DeleteItem(cItem);
SVM.CurrentNum = i;
}
SW.Close();
I also read about the Dispatcher, but i don't think it is very usable in this scenario, since there would be too much access to the main thread.
Any suggestions?
Thanks
I recommend reading the article (Build More Responsive Apps With The Dispatcher) from MSDN magazine that describes how WPF works with the Dispatcher when using BackgroundWorker.
You can pass the two collections and whatever else you'd like to worker threads as long as the objects you are accessing can be accessed from different threads.
int[] arrayofInt = new int[10]
ThreadPool.QueueUserWorkItem(s =>
{
//access the array in the worker thread
arrayofInt[0] = 10;
});
When finished with the work, you need to send a message to the dialog that it should be closed now. Do that by firing an event in your thread that is handled by your dialog.

Control.IsAccessible

I need to check if a c# WinForm Window (FORM Class) has been initialized and waiting for user events. But I could not find out how to manage that.
Therefore I had the idea to set the Control.IsAccessible Flag of the Form to true, within the OnLoad Event of the Windows Form.
My question is now, what is the Control.IsAccessible Flag origin intended for? Or is there an other solution to check if the Winform is initialized.
Thanks for your help
I do not know what IsAccessible is intended for but for the check you are doing you want Created
if(myForm.Created)
{
//Do stuff
}
I had a whole bunch of problems with it, here is one of my old question on SO that helped me out a lot with it.
Control.IsAccessible just means the control is visible to accessibility applications.
You can check myForm.Created to see if the window exists.
You can also register an event handler for the Application.Idle event, which occurs when the application has finished initializing and is ready to begin processing windows messages.
Here is a common usage:
public int Main(string[] args)
{
Application.Idle += WaitUntilInitialized;
}
private void WaitUntilInitialized(object source, EventArgs e)
{
// Avoid processing this method twice
Application.Idle -= WaitUntilInitialized;
// At this point, the UI is visible and waiting for user input.
// Begin work here.
}

WPF: How to handle errors with a BackgroundWorker

I am a bit of a newbie when it comes to windows client programming. I have a background worker that has a DoWork event and a RunCompleted event wired up. If an exception gets thrown in DoWork, I want to make changes to my UI, however, I cant because it is in a different thread. I can communicate the error to RunCompleted, but that doesn't help me either.
call Dispatcher.BeginInvoke. Basically, you want code like this:
void UpdateState(WhatEverType someObject)
{
if (! Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>UpdateState(someObject));
}
else
{
//make the UI changes here.
}
}

Update Label while processing in Windows Forms

What is the best way to update a label on a Windows Forms application while processing?
I have a loop that does some processing to files on the user's system when the user clicks a button.
foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
// Do processing
// Show progress bar
// Update Label on Form, "f.Name is done processing, now processing..."
}
What would be some sample code?
What exactly is this called? Is it threading or delegates?
A quick fix for you would be:
Label1.Text = f.Name + " is done processing, now processing...";
Label1.Refresh();
You really want to avoid DoEvents, otherwise you'll have problems if your user repeatedly presses buttons on your form.
You should be doing this on another thread, and then updating your UI thread from that thread. You are blocking further processing by performing this work on the UI thread.
If you can't move this code to the UI thread, then you could always call Application.DoEvents, but I strongly suggest you explore these options first:
System.ComponentModel.BackgroundWorker
System.Threading.ThreadPool
System.Threading.Thread
System.Threading.Tasks namespace
You'll need to get your data from one thread to the other. This can be done in a couple of ways...
First, your "background" thread could update some kind of "CurrentStatus" string variable that it changes as it goes along. You could then put a timer on your form that would then grab the CurrentStatus variable and update the label with it.
Second, you could simply invoke the operation from the background thread to the UI thread with a delegate using the InvokeRequired property of the label control. So for example...
private delegate void UpdateStatusDelegate(string status);
private void UpdateStatus(string status)
{
if (this.label1.InvokeRequired)
{
this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
return;
}
this.label1.Text = status;
}
You can call that UpdateStatus() method from any thread (UI or background), and it will detect whether or not it needs to invoke the operation on the main UI thread (and if so, does it).
To actually set up the thread, you can do so like this:
private void StartProcessing()
{
System.Threading.Thread procThread = new System.Threading.Thread(this.Process);
procThread.Start();
}
private void Process() // This is the actual method of the thread
{
foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
// Do processing
// Show progress bar
// Update Label on Form, "f.Name is done processing, now processing..."
UpdateStatus("Processing " + f.Name + "...");
}
}
Then when the user clicks the "GO" button you'll simply call StartProcessing().
If your processing is lengthy do it in a backgroundworker thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
I also recommend to use :
Application.DoEvents();
Processes all Windows messages currently in the message queue.

Resources