Friday 3 June 2016

Powershell_WPF - Part III - How to load a splash screen


What is a splash screen?
A splash screen is a graphical control element consisting of window containing an image, a logo and the current version of the software. A splash screen usually appears while a game or program is launching. According to Wikipedia J

That says everything there is to say. There’s nothing more to add I think.
More specifically, it's something like we see below:



What has that to do with us?

Well, you certainly had spent your time in scripting and writing tons of code in powershell and you found it funny. But at a certain point, you probably realize that the longer your script is, the more time it takes to load.
And before your computer, when you load your script, you’re like:


To sum up, if your application is too big, it will take time before your entire GUI is loaded and and you don't really want your user to wonder "hey! what's going on?". That’s where splash screen plays its role.

The idea of a splash screen came to me when I was asked to create a tool that wrapped ImageX for creating a WIM image. I realized that my tool took too much time to load and I needed something to keep the user busy.

How do we do it in Powershell?

The tips is: runspace

We are just going to use a runspace to load a second form before loading your code and close it when it’s finished. That is the big idea behind. You may be saying: what the heck is he talking about?
I only have a shallow knowledge about runspace too but, all I can say is that it’s really helpful when you want to do multi-threading (to have many processes working at the same time - in noobs way of speaking J).

In my previous post how to apply a theme in Powershell, I introduced Mahapps which uses a metro theme. We are going to use one of the component included in that theme for creating the splash screen. I think you’ve guessed it already: it’s for the progressbar in the splash screen.

Let’s move on to the code.

How to use the splash screen?

You just have to copy and paste the following code in your main ps1 file at the top. This way the runspace which contains the second form will be loaded before everything and can be called at any time inside the script.


If you want to add your logo and text, just edit:
$hash.Logo.Source=".\form\resources\powershel64x64.png"
$hash.LoadingLabel.Content= "Your Code is loading"  

As you can see, there are two functions:
- Start-splashScreen
- Close-splashScreen

Those functions are used to open and close the runspace.
You just have to put Start-splashScreen before the script block

Start-SplashScreen

try {

########################
# your incredible code
########################

}
catch{
    $ErrorMessage = $_.Exception.Message
    Write-Host $ErrorMessage
}

It’s better to use a try and catch if your code potentially generates error. So the splash screen will be closed in any case at the end.

And at the end of your file, before you call ShowDialog() on your form, or when the code you wanted to be executed is finished, close the splash screen.

close-SplashScreen
$Form.ShowDialog() | Out-Null

Of course, as you could understand, you can use a splash screen for many purposes. Let your imagination take you away.

Here is a little preview:


You can download all files here
And that’s it for this third part, hope you enjoyed it. J And see you in the next part

Share:

15 comments:

  1. Nice work Kevin. Did you figure out how to use the built-in dialogs in MahApps Metro using PowerShell?

    ReplyDelete
  2. Thank you! I haven't tried it yet because of the asynchronous tasks. But I will give it try and keep you informed.

    ReplyDelete
  3. Error loading assemblies (Code has not been modified):

    Exception calling "LoadFrom" with "1" argument(s): "Could not load file or assembly 'file:///C:\WINDOWS\system32\assembly\MahApps.Metro.dll'
    or one of its dependencies. The system cannot find the file specified."


    Using Load instead of LoadFrom results in different error:

    Exception calling "Load" with "1" argument(s): "Could not load file or assembly 'assembly\\MahApps.Metro.dll' or one of its dependencies. The
    given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)"

    In this case, it does find the files but says they are invalid.

    Any thoughts?
    Thanks.

    ReplyDelete
    Replies
    1. Hello Christopher,

      By looking at your error, I think it's related to the execution path.
      In this tutorial, I didn't use a relative path for assembly folder, that is why you have this problem.
      If you want to execute the script, you need to navigate to folder in PS console before.

      I stored my files at C:\ for example
      PS C:\PS_SplashScreen-master>
      So I need to navigate inside the folder to execute it:
      PS C:\PS_SplashScreen-master> powershell.exe .\form.ps1

      You cannot start it from another folder, so technically this won't work:
      PS C:\Windows\System32> powershell.exe -sta C:\PS_SplashScreen-master\form.ps1

      But of course you can use a relative path to avoid this little problem.

      And in this case, you cannot use the Load() method, because it's not the appropriate parameter.
      If you want to know more about how to load assembly in powershell, there's an excellent post here:
      http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html

      If you still have issues with the script don't hesitate.

      Kevin

      Delete
    2. Hi Kevin,

      I am also getting the same error
      Exception calling "LoadFrom" with "1" argument(s): "Could not load file or assembly file:///C:\WINDOWS\system32\assembly\MahApps.Metro.dll'

      I am running form.ps1 from the correct location and I also checked
      [System.Reflection.Assembly]::LoadFrom('assembly\MahApps.Metro.dll') | out-null
      is not commented out.
      Please suggest if I am missing anyting?

      Thanks
      Harikanth

      Delete
  4. Hello, exactly what I need, but $hash returns a null-value expression...

    ReplyDelete
    Replies
    1. Have you tried with the code on my Respoitory? https://github.com/dev4sys/PS_SplashScreen

      Delete
    2. I did.

      It does it when I call close-SplachScreen's function but nothing happen with the start-SplashScreen's, just waiting the 5 seconds before loading my form...

      Delete
  5. Exception calling "Load" with "1" argument(s): "Cannot create unknown type '{clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro}MetroWindow'."

    I am getting this error when just trying to run form1 from the current folder it's in..

    ReplyDelete
    Replies
    1. It looks like the assembly is not fully loaded.
      Could you check if this line is not commented:
      [System.Reflection.Assembly]::LoadFrom('assembly\MahApps.Metro.dll') | out-null
      If the problem still persist, feel free to send me an e-mail.

      Delete
  6. Very nice splash screen option. Is there a way to make $hash.LoadingLabel.Content= "Your Code is loading" dynamic? I was able to parse an $env:variable from the value of a parameter over to the new instance of pwoershell that handles the splash screen. However, I can't figure out how to make the LoadingLabel.Content information change without closing the splash screen and reopening it. Any ideas?

    ReplyDelete
    Replies
    1. Hi Benjamin!
      Of course you can update it dynamically.
      Basically you need to add something like this:
      $hash.window.Dispatcher.Invoke("Normal",[action]{ $hash.LoadingLabel.Content="New text"})
      If your variable is already in the runspace instance, there is no need to call the window.dispatcher.


      Delete
  7. Thank you very much for your work. I'm a Newbie at this.

    Can you show me how to change the background to an image ?

    Also how can I insert more lines of text in addition to "Your code is loading" ?

    Thank you.

    ReplyDelete
  8. I love the splash screen and I want to use it, but I am having a problem with closing the splash screen. As of right now I am using the code straight from GitHub to try it out and when it gets to the close function the splash screen stops animating and does not actually close the window. It doesn't continue to the rest of the script.

    ReplyDelete
    Replies
    1. That's because in the function close-SplashScreen the actual closing of the runspace is commented out:
      #$runspace.Close() | Out-Null

      This should be
      $runspace.Close() | Out-Null

      Delete

Popular Posts

Join us on Facebook

STATS

Contact Form

Name

Email *

Message *