WPF starting up interfaces without freezing the GUI - wpf

I know there is a bunch of threads about initializing stuff in a different thread so you dont need to freeze your UI. But in my case this initialization involves creating a lot of plots (polylines in a canvas) so it seems to need to freeze the UI.
It could be good enough to hide the frame where things are being initialized (I already let a "loading.." message in below) and freeze the UI then (couple of seconds) and then show again the frame.
This is what I have so far. But is not working... it freezes the UI before hiding nothing and it unfreezes after loading the fully initializes frame.
Otherwise the thing works like a charm.
void Historics_showExperimentResults(object sender, EventArgs e)
{
aepPage = new AEPPage();
resultsPage = new AEPResultSet();
// I try to hide the frame. Below there is a "Loading..." nice text.
// not sure if it's the best way but it works if I dont show anything at the end
ParadigmFrame.Dispatcher.Invoke((Action)delegate
{
ParadigmFrame.Content = null;
ParadigmFrame.UpdateLayout();
});
// This is the initialization that needs to have the GUI thread
//because it draw some plots and polylines
aepPage.Dispatcher.Invoke((Action)delegate
{
aepPage.init(resultSet);
});
//Then I want to go and visualize the initialized page with the plots
ParadigmFrame.Dispatcher.Invoke((Action)delegate
{
ParadigmFrame.Navigate(aepPage);
});
}
Any clue??? As I said I tried to put the init in a different thread and add a event when finished, but this threads needs the control over the UI for initializing the polylines in the canvas so .. it doesn't work :(
Thanks in advance !

It looks like Historics_showExperimentResults is already running on UI thread. Try this:
void Historics_showExperimentResults(object sender, EventArgs e)
{
aepPage = new AEPPage();
resultsPage = new AEPResultSet();
new Thread(_ =>
{
// I try to hide the frame. Below there is a "Loading..." nice text.
// not sure if it's the best way but it works if I dont show anything at the end
ParadigmFrame.Dispatcher.Invoke((Action)delegate
{
ParadigmFrame.Content = null;
ParadigmFrame.UpdateLayout();
});
// This is the initialization that needs to have the GUI thread
//because it draw some plots and polylines
aepPage.Dispatcher.Invoke((Action)delegate
{
aepPage.init(resultSet);
});
//Then I want to go and visualize the initialized page with the plots
ParadigmFrame.Dispatcher.Invoke((Action)delegate
{
ParadigmFrame.Navigate(aepPage);
});
}).Start();
}

I won´t mark this as an answer since it is not .. but still is the workaround I´m using right now.
What I did is split the fade out, the init and the fade in into pieces.
I created a storyboard, fade out and attach the next step to the Finished event so, in some kind of pseudocode it would be:
StoryBoard sb = new StoryBoard;
OnClick(object sender blabla)
{
storyBoard.add(fade out animation over ParadigmFrame);
storyBoard.Completed += performInit;
storyBoard.Begin();
}
So this part is executed and the paradigmFrame disappears showing the ¨Loading...¨ message that´s bellow.
Then ..
private blabla performInit()
{
aepPage.Dispatcher.Invoke((Action)delegate
{
aepPage.Finished += initFinished;
aepPage.init(resultSet);
});
}
For sure I created the Finished event in my aepPage class and fired it when the initialization is finished. So during all this process the UI is freeze. The "Loading..." message is visible and it is not awful but the REAL solution should not freeze the UI in here...
And then I show it up
private void initFinished()
{
storyBoard.add(fade in animation over ParadigmFrame);
storyBoard.Completed -= performInit;
storyBoard.Begin();
}
This is my long and ugly workaround ... I´m still open to new solutions !!!
Thanks !

Related

Updating WPF UI with BeginInvoke for Highspeed camera

I use ConcurrentQueue<Action> FrameActions where I add image frames that come from a high-speed camera - (60-90 FPS)
The Action contains methods to update the WritableBitmap image in UI.
For updating frames I use a separate thread which code is below
void FrameUIThread()
{
do
{
if (FrameActions.TryDequeue(out Action currentAction))
{
Application.Current.Dispatcher?.BeginInvoke(DispatcherPriority.Loaded, currentAction);
}
else
{
// DoEvents
Application.Current.Dispatcher?.Invoke(DispatcherPriority.Loaded, new Action(() => { }));
}
} while (true);
}
There was a problem that sometimes WritableBitmap is updated and a new image comes in, but the rest of the application - (all the buttons, counters and stuff are completely blocked, I can't click anything).
Found that using DoEvents - helps in this situation.
But now the flow of images is not smooth, but interrupted and goes spurts in some moments of time.
Is there any way to solve this problem?
Or could there be a better solution?

button content and wait cursor problems

I have a WPF application with a page with some code as shown below
public partial class MyPage : Page
{
public MyPage ()
{
InitializeComponent();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Cursor = Cursors.Wait;
this.btnClose.Content = "Cancel";
// some long time consuming processing
this.Cursor = Cursors.Arrow;
this.btnClose.Content = "Close";
}
}
I am doing two things here on the Close button click hander which are causing problems. Before long processing I change the button context text to Cancel. I also want to change cursor for whole page to wait. Once long processing is done I set the cursor state and button content back to where it was. However I am facing following two issues.
When application is doing long running operation, I don't get to see the button content as Cancel. It just keep showing me original content CLose.
The cursor changes to Arrow only on the button. However on rest of page,I still keep getting same arrow cursor.
Any ideas how can these issue be solved?
Your code runs on the UI thread by default, so nothing else can be executed on the UI thread (such as re-rendering the UI) until the thread finishes executing.
There are many ways of releasing control of the UI thread before the code finishes executing, but I find the simplest is to use a Task from the Task Parallel Library which can be used to run code on a separate thread.
For example,
// this runs on the main UI thread
this.Cursor = Cursors.Wait;
this.btnClose.Content = "Cancel";
Task.Factory.StartNew(() =>
{
// this code runs on a background thread
// some long time consuming processing
})
.ContinueWith((e) =>
{
// this code runs from the UI thread again
this.Cursor = Cursors.Arrow;
this.btnClose.Content = "Close";
});
It should be noted that UI objects can only be modified on the UI thread, which is why I put the second UI update in the .ContinueWith(...) of the task. An alternative to this would be to use the Dispatcher to ensure code gets executed on the UI thread. If you decide you need this instead and can't find an easy example via Google, let me know and I'll write one here.
This has to be a duplicate some where
public class WaitCursor : IDisposable
{
private Cursor _previousCursor;
public WaitCursor()
{
_previousCursor = Mouse.OverrideCursor;
Mouse.OverrideCursor = Cursors.Wait;
}
#region IDisposable Members
public void Dispose()
{
Mouse.OverrideCursor = _previousCursor;
}
#endregion
}
using (new WaitCursor())
{
// long blocking operation
}

Closing XNA from Windows Forms

I have a game running in XNA.
In order to create the menus and dialogs I am using windows forms.
My main issue - however, is with my 'Game Over' dialog.
When you die, a message appears asking if you want to try again. When you do - it opens up another instance of xna (so you have two running).
When you select 'Try Again' I would like the first to close and to open a second one.
XNA Game1.cs
GameOver gameover = new GameOver(level, levelManager, kills);
gameover.ShowDialog();
this.Exit();
'GameOver' is the name of the windows form that displays the game over stats.
(This takes the level that the user is on and starts the game at that level)
GameOver.cs (Windows form)
private void button1_Click(object sender, EventArgs e)
{
Visible = false;
Thread thread = new Thread(() =>
{
Game1 game = new Game1(level);
game.Run();
});
thread.Start();
thread.Join();
}
Any help is much appreciated.
i'll sum up the whole thing:
You need to write a reset method that will reset the game window. you can do it by taking all the code in the contractor and put them in another method and call that method in the constructor and in the reset method. make sure you don't leave anything off the reset. any member or connection that need to be initialized.
you can also open a new window and close the current one, but that's not the right way of doing things

How do I determine when Dispatcher.BeginInvoke completes?

I have a Silverlight 5 application that uses ImageTools for Silverlight to save a Canvas to a PNG image. I understand that I need to work with the Canvas on the UI thread and have the following code, which works:
if (saveFileDialog.ShowDialog() == true)
{
var stream = saveFileDialog.OpenFile();
writeableBitmap.Dispatcher.BeginInvoke(delegate
{
ExtendedImage extendedImage = writeableBitmap.ToImage();
new PngEncoder().Encode(extendedImage, stream);
});
}
The problem is that if the Canvas is very large it can take a noticeable time for the code in the BeginInvoke to complete. Since this is running on the UI thread it freezes the browser window during its execution.
After the user selects the location of where to save the exported image, I'd like to popup some child window that tells the user, "Please wait...", then run the image saving code posted above, and afterwards hide the child window automatically, but I'm not having much luck accomplishing that.
For starters, the BeginInvoke code runs asynchronously, so how do I know when it has completed?
If you need to call ToImage() on the UI Thread thats fine, but it doesnt mean you have to encode the image too.
Something like this will ensure the UI stays responsive.
if (saveFileDialog.ShowDialog() == true)
{
using (var stream = saveFileDialog.OpenFile())
{
writeableBitmap.Dispatcher.BeginInvoke(delegate
{
ExtendedImage extendedImage = writeableBitmap.ToImage();
System.Threading.ThreadPool.QueueUserWorkItem(item =>
{
new PngEncoder().Encode(extendedImage, stream);
});
});
}
}

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.
}

Resources