2009-09-01 72 views
1

好吧,我知道这已被问过一百万次之前(和人们也以XD的方式开始他们的StackOverflow问题),但我想知道如何实现如下:对于Winforms应用程序中的初始屏幕的不同要求

  1. 应用程序首先启动一个登录框
  2. 如果登录成功,则启动画面必须显示(在一个单独的线程)。
  3. 在显示启动画面时,必须填充一个类对象(这符合Singleton模式),其中包含大量来自DB的用户特定数据,同时向用户显示它正在做什么(例如,初始化。 .. loading data ... loading preferences ...渲染工作区...完成!)
  4. 启动画面还必须等待主窗体在主线程上完成初始化,然后才能最终处理。

这是应用程序的愿望流。关闭主窗体后,用户应该返回到登录框。

我必须指出,我并不是所有的人都知道winforms的东西,但通过提出这些问题,我正在慢慢地学习。我一直在读一些关于线程的知识,并且已经知道启动屏幕应该在自己的线程中产生,并且使用委托(来迎合UI的交叉线程更新)为主线程提供状态更新,并且这应该全部在“Main()”子程序的Program.cs中完成。

由于登录窗体先显示(最后在Main窗体关闭时显示),因此我甚至不知道从哪里开始。我当然会重视这方面的任何协助。

非常感谢! sha

回答

2

下面是一个简单的如何做到这一点的例子。诀窍是使登录框成为主窗体,因为它是首先打开并关闭的窗体。

对于本示例,LoginScreen窗体有一个按钮,一个OK按钮,单击时会调用OnOK()方法。

public partial class LoginScreen : System.Windows.Forms.Form 
{ 
    ApplicationWindow window; 

    public LoginScreen() 
    { 
     InitializeComponent(); 
    } 
    private void OnFormClosed(object sender, FormClosedEventArgs e) 
    { 
     this.Show(); 
    } 
    private void OnOK(object sender, EventArgs e) 
    { 
     this.Hide(); 

     window = new ApplicationWindow(); 
     window.FormClosed += OnFormClosed; 
     window.Show(); 
    } 
} 

ApplicationWindow窗体将等同于您所称的“主”窗体。它是启动SplashForm的。

public partial class ApplicationWindow : System.Windows.Forms.Form 
{ 
    public ApplicationWindow() 
    { 
     SplashForm.Show(500); 

     InitializeComponent(); 
    } 

    private void OnLoad(object sender, EventArgs e) 
    { 
     // Simulate doing a lot of work here. 
     System.Threading.Thread.Sleep(1000); 

     SplashForm.Hide(); 

     Show(); 
     Activate(); 
    } 
} 

这里是我使用的SplashForm的副本。它将根据您在静态Show()方法中指定的毫秒数来淡入和淡出。

public partial class SplashForm : Form 
{ 
    #region Public Methods 

    /// <summary> 
    /// Shows the splash screen with no fading effects. 
    /// </summary> 
    public new static void Show() 
    { 
     Show(0); 
    } 

    /// <summary> 
    /// Shows the splash screen. 
    /// </summary> 
    /// <param name="fadeTimeInMilliseconds">The time to fade 
    /// in the splash screen in milliseconds.</param> 
    public static void Show(int fadeTimeInMilliseconds) 
    { 
     // Only show the splash screen once. 
     if (_instance == null) { 
      _fadeTime = fadeTimeInMilliseconds; 
      _instance = new SplashForm(); 

      // Hide the form initially to avoid any pre-paint flicker. 
      _instance.Opacity = 0; 
      ((Form) _instance).Show(); 

      // Process the initial paint events. 
      Application.DoEvents(); 

      if (_fadeTime > 0) { 
       // Calculate the time interval that will be used to 
       // provide a smooth fading effect. 
       int fadeStep = (int) Math.Round((double) _fadeTime/20); 
       _instance.fadeTimer.Interval = fadeStep; 

       // Perform the fade in. 
       for (int ii = 0; ii <= _fadeTime; ii += fadeStep) { 
        Thread.Sleep(fadeStep); 
        _instance.Opacity += 0.05; 
       } 
      } else { 
       // Use the Tag property as a flag to indicate that the 
       // form is to be closed immediately when the user calls 
       // Hide(); 
       _instance.fadeTimer.Tag = new object(); 
      } 

      _instance.Opacity = 1; 
     } 
    } 

    /// <summary> 
    /// Closes the splash screen. 
    /// </summary> 
    public new static void Hide() 
    { 
     if (_instance != null) { 
      // Invoke the Close() method on the form's thread. 
      _instance.BeginInvoke(new MethodInvoker(_instance.Close)); 

      // Process the Close message on the form's thread. 
      Application.DoEvents(); 
     } 
    } 

    #endregion Public Methods 

    #region Constructors 

    /// <summary> 
    /// Initializes a new instance of the SplashForm class. 
    /// </summary> 
    public SplashForm() 
    { 
     InitializeComponent(); 

     Size = BackgroundImage.Size; 

     // If transparency is ever needed, set the color of the desired 
     // transparent portions of the bitmap to fuschia and then 
     // uncomment this code. 
     //Bitmap bitmap = new Bitmap(this.BackgroundImage); 
     //bitmap.MakeTransparent(System.Drawing.Color.Fuchsia); 
     //this.BackgroundImage = bitmap; 
    } 

    #endregion Constructors 

    #region Protected Methods 

    protected override void OnClosing(CancelEventArgs e) 
    { 
     base.OnClosing(e); 

     // Check to see if the form should be closed immediately. 
     if (fadeTimer.Tag != null) { 
      e.Cancel = false; 
      _instance = null; 
      return; 
     } 

     // Only use the timer to fade if the form is running. 
     // Otherwise, there will be no message pump. 
     if (Application.OpenForms.Count > 1) { 
      if (Opacity > 0) { 
       e.Cancel = true; // prevent the form from closing 
       Opacity -= 0.05; 

       // Use the timer to iteratively call the Close method. 
       fadeTimer.Start(); 
      } else { 
       fadeTimer.Stop(); 

       e.Cancel = false; 
       _instance = null; 
      } 
     } else { 
      if (Opacity > 0) { 
       Thread.Sleep(fadeTimer.Interval); 
       Opacity -= 0.05; 
       Close(); 
      } else { 
       e.Cancel = false; 
       _instance = null; 
      } 
     } 
    } 

    #endregion Protected Methods 

    #region Private Methods 

    private void OnTick(object sender, EventArgs e) 
    { 
     Close(); 
    } 

    #endregion Private Methods 

    #region Private Fields 

    private static SplashForm _instance = null; 
    private static int _fadeTime = 0; 

    #endregion Private Fields 
} 

的SplashForm只是一个空白窗体具有以下属性值:

  • 的BackgroundImage =(您所选择的图像)
  • BackgroundImageLayout =中心
  • DoubleBuffered =真
  • FormBorderStyle =无
  • ShowInTaskbar = False
  • 中StartPosition =中心屏幕
  • 最顶层=真

它还包含一个名为fadeTimer与默认性能System.Windows.Forms.Timer控制。 Tick事件被配置为调用OnTick()方法。

这不能做的是更新加载过程的状态。也许别人可以为你填写那部分内容。

+0

这不会在单独的线程中运行Splash Form,但另一个链接应该有帮助。 – 2009-09-01 20:07:26

+0

要与Splash Screen进行通信,可以在ApplicationWindow上监听事件,或者加载过程定期调用启动画面上的方法。如果启动画面在单独的线程中,请记住使用BeginInvoke。 – 2009-09-01 20:08:47

+0

你说得对。自从我看过这段代码以来已经有一段时间了。我会更新我的帖子以保持正确。谢谢。 – 2009-09-01 20:59:08