Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show loading window

My application in WPF loads external resources, so I want to show a loading form while the program is loading.

I tried to create the form, and show before the loading code, and close when loading ended.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
     LoadForm lf = new LoadForm();
     lf.Visibility = Visibility.Visible;

     // Al code that delays application loading

     lf.Close();
}

But the only thing I get is that the form is showed when loading progress is complete and immediately closes.

I think that I need to use System.Threading but not sure.

Thanks.

Note I load all application external resources in Window_Loaded() method and not in the main class method.

like image 322
FukYouAll Avatar asked Dec 12 '12 08:12

FukYouAll


3 Answers

You should look at this MSDN article on creating a SplashScreen in WPF. Essentially you add the Image you want to show to your project and set the Build Action to SplashScreen it will show when your program starts and disappear when your Main Application Window is shown.


You could also try importing the System.ComponentModel Class and use BackgroundWorker to Show your Loading Form, it will allow you to retain responsiveness of your UI.

public partial class MainWindow : Window
{
    Window1 splash;
    BackgroundWorker bg;
    public MainWindow()
    {

        InitializeComponent();

        bg = new BackgroundWorker();
        bg.DoWork += new DoWorkEventHandler(bg_DoWork);
        bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);

    }

    void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        splash.Hide();
    }

    void bg_DoWork(object sender, DoWorkEventArgs e)
    {
        System.Threading.Thread.Sleep(10000);
    }


    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        splash = new Window1();
        splash.Show();
        bg.RunWorkerAsync();
    }
}
like image 50
Mark Hall Avatar answered Nov 10 '22 10:11

Mark Hall


You should put your time consuming code in a background thread (for that you can use BackgroundWorker, Task or Async Await, depending on your dot net framework version)

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    LoadForm lf = new LoadForm();
    lf.Visibility = Visibility.Visible;
    //start the time consuming task in another thread
}


HeavyTaskCompleteEvent()
{
     lf.Close();
}

Also look out for the best way to show loading screen. You can show some animation in the main window as well. I don't think showing a form is the best way.

like image 2
Haris Hasan Avatar answered Nov 10 '22 11:11

Haris Hasan


I made a Loader class a while ago you could use. It shows a Window while doing your loading-method, closes it when completed and gives you the output of the method:

public class Loader<TActionResult>:FrameworkElement
{
    private Func<TActionResult> _execute;
    public TActionResult Result { get; private set; }
    public delegate void OnJobFinished(object sender, TActionResult result);
    public event OnJobFinished JobFinished;

    public Loader(Func<TActionResult> execute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
    }

    private Window GetWaitWindow()
    {
        Window waitWindow = new Window { Height = 100, Width = 200, WindowStartupLocation = WindowStartupLocation.CenterScreen, WindowStyle = WindowStyle.None };
        waitWindow.Content = new TextBlock { Text = "Please Wait", FontSize = 30, FontWeight = FontWeights.Bold, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };

        return waitWindow;
    }

    public void Load(Window waitWindow = null)
    {
        if (waitWindow == null)
        {
            waitWindow = GetWaitWindow();
        }
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += delegate
        {
            Dispatcher.BeginInvoke(new Action(delegate { waitWindow.ShowDialog(); }));
            Result = _execute();
            Dispatcher.BeginInvoke(new Action(delegate() { waitWindow.Close(); }));
        };
        worker.RunWorkerCompleted += delegate
        {
            worker.Dispose();
            if (JobFinished != null)
            {
                JobFinished(this, Result);
            }
        };
        worker.RunWorkerAsync();
    }
}

How to use it:

Loader<TResult> loader = new Loader<TResult>(MethodName);
loader.JobFinished += new Loader<TResult>.OnJobFinished(loader_JobFinished);
loader.Load();

void loader_JobFinished(object sender, TResult result)
{
    // do whatever you want with your result here
}
like image 1
Florian Gl Avatar answered Nov 10 '22 10:11

Florian Gl