6

给定下面的类,在备用线程上启动启动屏幕:

public partial class SplashForm : Form
{
    private static Thread _splashThread;
    private static SplashForm _splashForm;    

    public SplashForm()
    {
        InitializeComponent();
    }

    // Show the Splash Screen (Loading...)      
    public static void ShowSplash()    
    {        
        if (_splashThread == null)        
        {            
            // Show the form in a new thread.          
            _splashThread = new Thread(new ThreadStart(DoShowSplash));            
            _splashThread.IsBackground = true;            
            _splashThread.Start();        
        }    
    }    

    // Called by the thread.  
    private static void DoShowSplash()    
    {        
        if (_splashForm == null)            
            _splashForm = new SplashForm();       

        // Create a new message pump on this thread (started from ShowSplash).       
        Application.Run(_splashForm);
    }    

    // Close the splash (Loading...) screen.
    public static void CloseSplash()    
    {        
        // Need to call on the thread that launched this splash.      
        if (_splashForm.InvokeRequired)            
            _splashForm.Invoke(new MethodInvoker(CloseSplash));        
        else            
            Application.ExitThread();    
    }
}

使用以下相应命令调用并关闭它

SplashForm.ShowSplash();
SplashForm.CloseSplash();

美好的。

我对 TPL 并不陌生,当然我们可以使用以下简单的方法在另一个线程上显示表单:

Task task = Task.Factory.StartNew(() => 
{
    SomeForm someForm = new SomeForm();
    someForm.ShowDialog();
};

我的问题是SomeForm当你准备好时关闭它。必须有比public staticSomeForm类中创建方法更好的方法

private static SomeForm _someForm;
public static void CloseSomeForm()    
{        
    if (_someForm.InvokeRequired)            
        _someForm.Invoke(new MethodInvoker(CloseSomeForm));        
}

我的问题是,使用上面使用任务并行库 (TPL) 的 SplashForm 类执行相同操作的最佳方法是什么?具体来说,关闭 UI 中另一个线程上调用的表单的最佳方式。

4

2 回答 2

2

您的问题似乎与和之间的区别不大ThreadTask因为您想要摆脱“肮脏”的静态状态。我建议你将它封装到一个类中:

class SplashController
{
    public void Run() {
        _someForm = new SomeForm();
        someForm.ShowDialog();
    }

    private SomeForm _someForm;
    public void CloseSomeForm()    
    {        
        if (_someForm.InvokeRequired)            
            _someForm.Invoke(new MethodInvoker(CloseSomeForm));        
    }
}

您可以使用您喜欢的任何线程机制调用 Run。CloseSomeForm 不使用线程,因此它与此问题无关。

您现在可以存储对SplashController任何您喜欢的实例的引用。在局部变量中或实际上在静态变量中。后者是有道理的,因为只有一个启动画面。

因为现在已经很好地封装了静态状态,所以我认为静态保持它没有任何问题。

于 2013-03-08T16:42:28.063 回答
2

你可能不应该做这样的事情

Task task = Task.Factory.StartNew(() => 
{
    SomeForm someForm = new SomeForm();
    someForm.ShowDialog();
};

因为它需要一个消息循环出现在创建表单的确切线程上,这是一个线程池线程。但我没有测试过这个。

你可以试试这个:

public static Task<SplashForm> ShowSplash()    
{        
    var tcs = new TaskCompletionSource<SplashForm>();

    // Show the form in a new thread.          
    _splashThread = new Thread(() =>
    {
        var splashForm = new SplashForm();       

        tcs.SetResult(_splashForm);

        // Create a new message pump on this thread (started from ShowSplash).       
        Application.Run(splashForm);
    });

    _splashThread.IsBackground = true;            
    _splashThread.Start();        
}    

这将允许您从 CloseSplash 中删除静态修饰符:

// Close the splash (Loading...) screen.
public void CloseSplash()    
{        
    // Need to call on the thread that launched this splash.      
    if (this.InvokeRequired)            
        this.Invoke(new MethodInvoker(CloseSplash));        
    else            
        Application.ExitThread();    
}

可以这样使用:

var form = await SplashForm.ShowSplash();
form.CloseSplash();
于 2013-03-08T16:52:12.623 回答