Wait screen during rendering UIElement in WPF - c#

I have a WPF application using PRISM. I have a login screen and on successfuly logging in a new view containing a TileListView with many items appears. This needs over 10 seconds to render because control has to calculate a lot etc. All this uses the UI thread by standard behaviour, because rendering in WPF is done in UI thread. Is it possible to display a WaitControl like a spinner or just a simple animation in seperate window or something like this? Now to animation stops at the time, the control is rendered in UI Thread.

You could create a new window that launches in a separate thread. Please refer to the following blog post for an example of how to do this.
Launching a WPF Window in a Separate Thread: http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/
Then you just start this thread that displays the window just after you have validated the credentials and just before your heavy rendering is about to begin.
This is probably the best thing you can do and it should also be a pretty easy thing to implement.
Edit - Including code from above link to be recorded for posterity:
using System.Threading;
using System.Windows.Threading;
void LoadWindowInThread()
{
Thread newWindowThread = new Thread(new ThreadStart(() =>
{
// Create our context, and install it:
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
// Create and configure the window
Window1 tempWindow = new Window1();
// When the window closes, shut down the dispatcher
tempWindow.Closed += (s, e) =>
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
tempWindow.Show();
// Start the Dispatcher Processing
Dispatcher.Run();
}));
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
}

you can use SplashScreen to display untill the background process is completed. Refer this Splash Screen in WPF

Related

XAML window inside winforms program

When I use a button on a form for Winforms to open a window made in XAML the first time it works with no issues, then I close the window and re-click the button, but on the InitializeComponent() for the window being created I get an exception with the message, "The Application object is being shut down".
//code on button press is this
var rs = new RestoreSettings();
rs.Show();
I have tried hosting it as a user control inside an element host still the same issue.
In a normal application both the WinForms and WPF environment is kickstarted by an Application type, which is typically called from the Main method.
Here this does not happen for the WPF environment, which causes problems. If you want to show a WPF window from a WinForms application you need to boot up the dispatcher. Best to do this in a new thread so it can be shut down as many times as you want:
private void ShowWpfWindow()
{
// This delegate is executed in new thread
ThreadStart showWindow = () =>
{
var window = new RestoreSettingsWindow(); // your window to show
// making sure that the thread can exit when the window is closed
window.Closed += (sender, e) => Dispatcher.InvokeShutdown();
window.Show();
// Starts the dispatcher in the new thread and does not let the thread exit.
// This call is returned when the window is closed (due to the Closed event handler)
System.Windows.Threading.Dispatcher.Run();
};
// Creating and starting an STA thread for the WPF window
Thread wpfThread = new Thread(showWindow);
wpfThread.SetApartmentState(ApartmentState.STA);
wpfThread.Priority = ThreadPriority.Normal;
wpfThread.Start();
}

Better way of doing Splash Screen

at the moment I got this
UPDATED: Thanks for all the answers.
private void Form1_Load(object sender, EventArgs e)
{
//hide() doesnt help
Thread init = new Thread(InitApplication);
init.IsBackground = true;
init.Start();
}
InitApplication takes at least 5+ seconds to complete and write in all the settings. I want my splashScreen to stay up until then.
ADDED:
private readonly SplashScreen _splash;
public Form1(SplashScreen splashy)
{
_splash = splashy;
InitializeComponent();
}
and I got
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashScreen splashy = new SplashScreen();
splashy.Show();
Application.DoEvents();
Application.Run(new Form1(splashy));
}
It is doing what its suppose to do, However, Now I see form1 on top of the splashform. Where can I add the hide and show method so it only the splash screen is shown and form1 popups when its fully loaded.
Try loading the splash screen from the UI thread, then use a background worker to execute InitApplication(). The background worker can communicate progress to the UI thread.
BackgroundWorker Class on MSDN
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.
You can use Async Await, Background worker or Thread for initializing your app etc. These are written in the sequence of easy to use and the general pattern being followed.
Use a normal windows form and there use progress bar, gif image etc. what you like most there. On the form load or form shown event start the background task and when it finishes, close the normal form and load your main application form.
If your InitApplication has any call that deals with GUI, you will have to change that call and Invoke the desired action on GUI thread.

Controls not loading when multithreading a form

I have a C# WinForms application. When the main form loads, two other forms are loaded and hidden as I need them to run in the background. I keep 2 global variables pointing to them in order to be able to access them. I want to load them on a separate thread to reduce the loading time. For this, I have the following code in the main form's constructor:
if (!IsHandleCreated)
{
CreateHandle();
}
//Start the license manager using a separate thread.
new Thread(delegate()
{
BeginInvoke(new Action(() =>
{
GlobalVariables.licenseManagerWindow = new LicenseManager();
GlobalVariables.licenseManagerWindow.Show();
}));
bt_Licenses.BeginInvoke(new Action(() =>
{
bt_Licenses.Enabled = true;
}));
}).Start();
//Start the employee app manager using a separate thread.
new Thread(delegate()
{
BeginInvoke(new Action(() =>
{
GlobalVariables.employeeAppManagerWindow = new ManageEmployeeApp();
GlobalVariables.employeeAppManagerWindow.Show();
}));
bt_Employees.BeginInvoke(new Action(() =>
{
bt_EmployeeApp.Enabled = true;
}));
}).Start();
The problem is that instead of showing the main form and updating the buttons after each form is loaded, the main form looks like this until both of the other forms are loaded:
As you can see, the controls don't load and they show transparently. Eventually they all load fine when the 2 forms load. If I comment out the code above, the main form loads perfectly fine. I obviously don't want the user to see this skeleton while the forms load, but to see the controls. What am I doing wrong?
Try using background workers instead of threads. use the report progress / runworkercomplete events to write the results to your form. This prevents your UI waiting with the draw until the threads are completed and makes it that you don't have to manually handle the invokes of controls.
documentation and examples can be found here: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx
Instead of loading the two hidden forms in the main form's constructor, do it in the main form's "Load" event handler.
Windows forces you to load the hidden forms through the main thread (that's what BeginInvoke does), but you can minimize the impact to the main thread by having the hidden forms kick off the long-running network communication on a background thread from the hidden forms' "Load" event.

Background Worker in windows form application C# does not block UI

I am using background worker in my win form application I am showing progress bar form for a long running process and that long running process is on background worker.
Note: I have used background worker for showing progress bar in marquee style.
Problem I am facing is due to background worker my User interface gets responsive, but I don't want it to be responsive.
My code is as below:
ProgressBarForm progForm = new ProgressBarForm();
progForm.Show();
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork+= myMethod;
worker.RunWorkerAsync();
Considering that you are using a form to display the progress, you can use ShowDialog instead of Show. This will open the window as a modal dialog, blocking UI actions to your underlying window until the progress window is closed.
Some things to consider:
ShowDialog is a blocking call, so call it after starting the background worker.
Make sure the user can't close the window, and programmatically close the window yourself after the background worker completes.
If you don't want your user interface to be used, set .Enabled = false; on each of the form controls, then reverse the changes in _RunWorkerCompleted.
Just remember to leave any cancel / close buttons enabled :)

How to run an animated SplashScreen at the same time as a Bootstrapper on STA threads

Background:
I am working on a WPF application that uses the MEF framework to automatically link the necessary libraries and components for the app. With people adding their own components, the loading takes anywhere from 0-2 seconds to 6-7 seconds on slower machines. For this, I think a nice splash screen to let the user know the application is loading would be necessary. Ideally the splash screen would display an animated progress bar as well as a status text field describing which components are being loaded.
Problem:
I designed a splash screen window that is called right at the start of the application (OnStartup), followed by the loading of the MEF bootstrapper. Problem is of course, the window does not animate because it is on the same thread as the MEF bootstrapper loading. I tried putting the bootstrapper on a separate thread but it complains that it is not an STA thread. Even on an STA thread it still didn't like it and it threw errors when trying to load the main app window. I can't put the splash screen window itself on a separate thread because then I don't have access to it, and it has to be an STA thread also because its a UI component. (Realized this is untrue, I can talk to the thread)
Update
I found a solution where I kept the splash screen window in a separate STA thread. Thank you everyone who replied for pointing me in the right direction:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Dispatcher threadDispacher = null;
Thread thread = new Thread((ThreadStart)delegate
{
threadDispacher = Dispatcher.CurrentDispatcher;
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(threadDispacher));
loadingWindow = new LoadingWindow();
loadingWindow.Closed += (s, ev) => threadDispacher.BeginInvokeShutdown(DispatcherPriority.Background);
loadingWindow.Show();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
var bootstrapper = new Bootstrapper();
bootstrapper.Run();
if (threadDispacher != null)
{
threadDispacher.BeginInvoke(new Action(delegate { loadingWindow.Close(); }));
}
}
You were on the right way moving the bootstrapper to a thread of its own.
What you should do, however is make sure that the portions that require being executed on the UI thread are also invoked on the UI thread.
So when the MEF bootstrapper is done, you can invoke the hiding of the splash window and opening of the main window on the main thread, even from the MEF's thread.
A way to get your message across to the main thread is by dispatcher

Categories