线程类'Splash-Type'屏幕的TPL等价物

时间:2013-03-08 16:35:26

标签: c# task-parallel-library

鉴于下面的课程,要在备用线程上启动启动画面:

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 static类中创建SomeForm方法更好的方法,例如

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

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

2 个答案:

答案 0 :(得分: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实例的引用。在局部变量中或实际上在静态变量中。后者是有道理的,因为只有一个闪屏。

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

答案 1 :(得分:2)

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

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

因为它需要在创建Form的确切线程上存在消息循环,这是一个ThreadPool线程。但我没有测试过这个。

你可以试试这个:

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中删除static修饰符:

// 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();