 |
|
 |
Thank you,I find this article very useful
|
|
|
|
 |
|
 |
Thank you very much for that really working piece of software !!
Paolo Saudin
|
|
|
|
 |
|
 |
Hi,
3 problems:
1) If you run this as a compiled app, by double clicking the .exe in explorer, when the splash screen closes, the main form appears behind the explorer window. I've played around with it a bit, and can't fix this. I even tried adding a delay in the splash screen close so that the main form was displayed before the splash screen closed. When I did this, the main form displayed correctly (behind the splash screen but in front of the explorer window) but as soon as the splash screen was closed and the message pump ended the explorer window took focus.
2) If you attempt to set the status on the splash screen form before the thread has finished loading the splash screen you get an exception. This doesn't happen very often. It's a race condition between the main thread and the thread that's creating the splash form. You can make it more likely to happen by putting a Thread.Sleep(1000) in the splash screen creation thread.
3) You are swallowing all exceptions in the close method. This is very bad practise. What exceptions are you expecting here?
Simon
|
|
|
|
 |
|
 |
Hi,
which problems can I expect if I don't run the splash thread in an STA, just leaving out the line
//m_SplashThread.SetApartmentState(ApartmentState.STA); ?
For the moment, I have the problem that my splash screen locks up whenever I launch another (3d party) application during the splash screen. The problem may well be in the 3d party application, which is an unmanaged C++ app accessing COM objects, but I can't change anything on that side.
Everything seems to work ok when I leave out the ApartmentState.STA, but not sure what other problem can arise then.
Thanks.
|
|
|
|
 |
|
 |
using System;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
namespace SplashScreen
{
public class Splasher
{
private static Form m_SplashForm = null;
private static ISplashForm m_SplashInterface = null;
private static Thread m_SplashThread = null;
private static string m_TempStatus = string.Empty;
/// <summary>
/// Show the SplashForm
/// </summary>
public static void Show(Type splashFormType)
{
if (m_SplashThread != null)
return;
if (splashFormType == null)
{
throw (new Exception("splashFormType is null"));
}
m_SplashThread = new Thread(new ThreadStart(delegate()
{
CreateInstance(splashFormType);
Application.Run(m_SplashForm);
}));
m_SplashThread.IsBackground = true;
m_SplashThread.SetApartmentState(ApartmentState.STA);
m_SplashThread.Start();
}
/// <summary>
/// set the loading Status
/// </summary>
public static string Status
{
set
{
if (m_SplashInterface == null || m_SplashForm == null)
{
m_TempStatus = value;
return;
}
//??? System.InvalidOperationException
//Message="?????????,???????? Invoke ? BeginInvoke?"
//Source="System.Windows.Forms"
//StackTrace:
// ? System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
// ? System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
// ? SplashScreen.Splasher.set_Status(String value) ?? D:\MyComponent\CSplash\SplashScreen\Splasher.cs:?? 55
// ? SplashScreen.frmMain..ctor() ?? D:\MyComponent\CSplash\SplashScreen\frmMain.cs:?? 27
// ? SplashScreen.Program.Main() ?? D:\MyComponent\CSplash\SplashScreen\Program.cs:?? 22
// ? System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
// ? System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
// ? Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
// ? System.Threading.ThreadHelper.ThreadStart_Context(Object state)
// ? System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
// ? System.Threading.ThreadHelper.ThreadStart()
m_SplashForm.Invoke(
new SplashStatusChangedHandle(delegate(string str) { m_SplashInterface.SetStatusInfo(str); }),
new object[] { value }
);
}
}
/// <summary>
/// Colse the SplashForm
/// </summary>
public static void Close()
{
if (m_SplashThread == null || m_SplashForm == null) return;
try
{
m_SplashForm.Invoke(new MethodInvoker(m_SplashFormClose));
}
catch (Exception)
{
}
m_SplashThread = null;
m_SplashForm = null;
}
private static void CreateInstance(Type FormType)
{
object obj = FormType.InvokeMember(null,
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);
m_SplashForm = obj as Form;
m_SplashInterface = obj as ISplashForm;
if (m_SplashForm == null)
{
throw (new Exception("Splash Screen must inherit from System.Windows.Forms.Form"));
}
if (m_SplashInterface == null)
{
throw (new Exception("must implement interface ISplashForm"));
}
if (!string.IsNullOrEmpty(m_TempStatus))
m_SplashInterface.SetStatusInfo(m_TempStatus);
}
private delegate void SplashStatusChangedHandle(string NewStatusInfo);
private static System.Threading.ManualResetEvent mrEvent;
public static void m_SplashFormClose( )
{
//// flag the DrawSplashWindow thread to exit
//mrEvent.Set();
mrEvent = new System.Threading.ManualResetEvent(false);
mrEvent.WaitOne(100, true);
//fader loop
for (double i = 100.0; i >= 0.0; i -= 5.0) // run opacity index
{
//?????,???? :
// System.InvalidOperationException
//"???????: ???????“frmSplash”???????"
// CheckForIllegalCrossThreadCalls = false; ???
m_SplashForm.Opacity = i / 100.0;// decrease opacity
System.Threading.Thread.Sleep(25);
}
mrEvent.Set();
m_SplashForm.Close();
}
}
}
we can do this !
?!?|~~~~~~~~~~|!
dghjdghjtryurtrd
|
|
|
|
 |
|
 |
I've tried a few of the splash screen projects - had issues with some - What I like about solution is that it worked first time and there were no hassles... My Type of project.
Well done
Al
|
|
|
|
 |
|
 |
There is an error when I press alt + F4 while SplashScreen was showing.
This project is same the project on the page http://www.codeproject.com/csharp/apploadingarticle.asp
-- modified at 3:39 Friday 26th October, 2007
|
|
|
|
 |
|
 |
maybe the following snippet is quick & dirty, but it works for me!
you can implement the following code into your frmSplash.cs:
//add event-handler
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SplashForm_FormClosing);
//method: cancel closing routine
private void SplashForm_FormClosing(object sender, FormClosingEventArgs e)
{
//cancel closing routine
e.Cancel = true;
}
that's all - hope this helps!
BTW: great and easy splashscreen implementation - thanks a lot!
greets,
chris
|
|
|
|
 |
|
 |
cann't do this way
e.Cancel = true;
it will make splashform that can not close
splashform .close() cann't work
dghjdghjtryurtrd
|
|
|
|
 |
|
 |
nice and useable, thanks!
Just another style...
|
|
|
|
 |
|
 |
This article is really great, it helped me very much in quickly have a splash screen which behaves and I can easily control ... sincere compliments for this great work !
This article is " must read" for everyone which deals with winapps, IMHO.
It helped me in quickly understand (and then implement) how to
- create a Splash object shortly after startup of myapp
- have the Splash object behaving smoothly (independent thread)
- control the Splash obejct from the "Main_Load" ...
I already had a Frame with the BouncingProgressBar, however the problem I was facing was that the bouncing was behaving in a non-smooth way. The reason for that was that it was not running in its own thread (I guess).
The conceptual solution shown in this great article and excellent code was (for me) in the following steps:
a) create a "Splasher" class [copy/pasted form here]
b) extend my SplashScreen by adding the ISplashForm interface
c) modify Program.cs so that Splasher is started Application.Run
d) modify my application so that when it is "ready" it closes the Splasher
Compliments again !!!!
|
|
|
|
 |
|
 |
Hello,
First, thanks for this great example.
I want to add a connection to SQL server, during splash. I do the following:
Sub New()
InitializeComponent()
Splasher.Status = "Creating MainForm..."
System.Threading.Thread.Sleep(1000)
Splasher.Status = "Loading Files..."
System.Threading.Thread.Sleep(1500)
Splasher.Status = "Loading Plug/Ins..."
System.Threading.Thread.Sleep(1500)
Splasher.Status = "Connecting to SQL Server..."
If Not ConnectToSQL() Then Exit Sub
Splasher.Status = "Sleeping 1 second..."
System.Threading.Thread.Sleep(1000)
Splasher.Close()
End Sub
ConnectToSQL function is implemented in Module.
When I get to this line, during debug, I see that the label StatusInfo shows the first status again (Creating MainForm...,Loading Files...,Loading Plug/Ins...)
and after that I get an error ("Invoke or BeginInvoke cannot be called on a control until the window handle has been created.") into "Public Shared WriteOnly Property Status" property.
What is wrong?
Thanks.
Eric H.
|
|
|
|
 |
|
 |
You really saved me a lot of time. Thanks!
|
|
|
|
 |
|
 |
A very good article - nice and short! Thanks.
|
|
|
|
 |
|
 |
Excellant tool. The Threading is a nice touch over what i'd done. It's definitely going into my library. I'm attempting to do some things to make it more runtime customizable though. For example adding a progress bar, and replacing the hard text in the image with labels... Attempting to do that has sparked a couple of questions. And forgive me if these are newbie questions. I haven't used interfaces/delegates like this before..
1. Removing SetCompatibleTextRenderingDefault and EnableVisualStyles does not seem to have any effect. Should they? I'd like to use this in Add-Ins and read that SetCompatibleTextRenderingDefault shouldn't be used in Add-ins.
2. After removing all of the text from the image I added labels in the appropriate locations. Where' I'm getting lost at is where do I set there values at? It doesn't make sense to reset them everytime the status updates most of these labels will be static within each call. Do I have to create an interface/delegate for each label? Any insight would be appreciated.
_________________________________________________________
"I have found the paradox that if I code until it hurts, then there is no hurt, but only more code". Mother Teresa (if she were a coder)
|
|
|
|
 |
|
 |
not that I'm lazy, just running into a few conversion errors.
The c# version works great with the sample form. If I am able to integrate this into my vb.net solution it might will solve exactly the problem you stated...
"Sometimes,we had to put a lot of initialization code into the MainForm's OnLoad() override.So that,when the application started up,it looked like a mess" This is exactly my problem and there doesn't seem to be an easy way around it. I tried making the form invisible until it was all done initialising or moving the location to some x,y coordinate close to the moon...but nothing has worked.
greg
|
|
|
|
 |
|
 |
how would this translate...
m_SplashThread = new Thread(new ThreadStart(delegate(){CreateInstance(splashFormType);
Application.Run(m_SplashForm);
}));
|
|
|
|
 |
|
 |
Private Shared m_SplashFormType As Type = Nothing
Public Shared Sub Show(ByVal splashFormType As Type)
If Not (m_SplashThread Is Nothing) Then
Return
End If
If splashFormType Is Nothing Then
Throw New Exception("splashFormType is null")
End If
m_SplashFormType = splashFormType
m_SplashThread = New Thread(New ThreadStart(AddressOf Method4SplashThread)) '
m_SplashThread.IsBackground = True
m_SplashThread.SetApartmentState(ApartmentState.STA)
m_SplashThread.Start()
End Sub
Public Shared Sub Method4SplashThread()
CreateInstance(m_SplashFormType)
Application.Run(m_SplashForm)
End Sub
|
|
|
|
 |
|
 |
Hi,
This is a good sample, but it always show on top of all application. Such as I open your splash screen and then I switch to outlook.
The splash screen still show on the top layer. It may cause of problem when user want to read his email during open the application.
Just a suggestion.
mj
|
|
|
|
 |
|
 |
Nice Application so far, but after Splasher.Close() the Mainform will not appear on Top. If you have several Application Windows running, and start the Splash App, only the Splasher will shown on top, but the Mainform Window appears behind existing Windows. This is a little bit confusing.
To solve this problem just add the following Lines in your Mainform:
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
public MainForm()
{
Splasher.Status = "Initialize Application...";
InitializeComponent();
Splasher.Close();
IntPtr hWnd = this.Handle;
SetForegroundWindow(hWnd);
}
|
|
|
|
 |
|
 |
Don't forget to include using System.Runtime.InteropServices;
----
Navigator - Your best alternative to Windows Explorer
|
|
|
|
 |
|
 |
you show the splash, close, then show again, close, and you will see the splash did NOT disappear.
it happen occasionally.
Regards,
unruledboy@hotmail.com
|
|
|
|
 |
|
 |
This example is great
I have been trying to figure this out for the past 3 days without success.
However, I am not able to use this in my project because I have problems converting them to VB syntax.
esp this line ...
m_SplashForm.Invoke(
new SplashStatusChangedHandle(delegate(string str) { m_SplashInterface.SetStatusInfo(str); }),
new object[] { value }
);
Any help will be appreciated.
|
|
|
|
 |
|
 |
The converting erros to have been mainly caused by Anonymous Method in C#2.0. I translate the core code into VB.NET syntax as follows:
Shared Sub AnonymousMethodDelegate(ByVal NewStatusInfo As String)
m_SplashInterface.SetStatusInfo(NewStatusInfo)
End Sub
Public Shared WriteOnly Property Status() As String
Set(ByVal value As String)
If ((Splasher.m_SplashInterface Is Nothing) OrElse (Splasher.m_SplashForm Is Nothing)) Then
Splasher.m_TempStatus = value
Else
Splasher.m_SplashForm.Invoke(New SplashStatusChangedHandle(AddressOf AnonymousMethodDelegate), New Object() {value})
End If
End Set
End Property
Private Delegate Sub SplashStatusChangedHandle(ByVal NewStatusInfo As String)
|
|
|
|
 |
|
 |
Brilliant. Thank you for the quick response.
|
|
|
|
 |