在Form_Load

时间:2015-09-02 19:11:18

标签: c# winforms

我正在使用实用程序将目录复制到多个USB记忆棒。当Form1加载时,我希望标签显示状态"检测磁盘驱动器...",然后调用方法来读取驱动器并用信息填充表单。我有它工作,除了表单加载它在显示标签之前调用方法。因此它似乎挂起(标签实际上是灰色背景上的白色框)。我尝试了计时器和线程以及我能想到的每一个,每个都有不同的死胡同。在调用读取驱动器的方法之前,我还没有找到更新标签的方法。

方法getAndDisplayData()等待'挂起'我的节目。我希望在表单更新lblDisplayStatus.Text的文本后才能调用它

我也不希望用户在调用方法之前必须与表单进行交互。

这是我的C#代码:

    private void USB_Utility_Load(object sender, EventArgs e)
    {
        lblDisplayStatus.Text = "Detecting Disk Drives...";
    }

    private void tabUSB_Prep_Enter(object sender, EventArgs e)
    {
        tabUSB_Prep.Controls.Clear();
        getAndDisplayData();
    }

非常感谢任何帮助。

以下是我最终的代码:

    BackgroundWorker _worker;

    private void USB_Utility_Load(object sender, EventArgs e)
    {
        _worker = new BackgroundWorker(); // Should be a field on the form.
        _worker.DoWork += DoWork;
        _worker.RunWorkerCompleted += RunWorkerCompleted;
        lblDisplayStatus.Text = "Detecting Disk Drives...";
        _worker.RunWorkerAsync();
    }

    //Background Worker
    private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        lblDisplayStatus.Text = "Done...";
        displayData();
    }

    private void DoWork(object sender, DoWorkEventArgs e)
    {
        getData();
    }

3 个答案:

答案 0 :(得分:0)

老式的方法是使用BackgroundWorkergetAndDisplayData中运行阻止工作,然后在启动worker之前更新标签,并在worker完成时再次更新。

现在 - 我认为你也可以使用任务来获得完全相同的结果,但我还没有真正尝试过,因为WinForms通常不是新项目的首选。

   BackgroundWorker _worker;

   public void Form_Load(object sender, EventArgs e) {
       _worker = new BackgroundWorker(); // Should be a field on the form.
       _worker.DoWork += DoWork;
       _worker.RunWorkerCompleted += RunWorkerCompleted;
       lblDisplayStatus.Text = "Detecting Disk Drives...";
       _worker.RunWorkerAsync();
   }

   private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)   {
     lblDisplayStatus.Text = "Done...";       
    }

   private void DoWork(object sender, DoWorkEventArgs e) {
       getAndDisplayData();
   }

About background workers

答案 1 :(得分:0)

如果要使用新的(ish)async / await模式,则需要使用TaskScheduler从原始线程更新UI。这是一个例子:

// clear the form
tabUSB_Prep.Controls.Clear();

// This is just to show crossing a "context" works
string test = "";

// get the UI's current TaskScheduler
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();

// This can be used to wrap a method that doesn't 
// directly implement async/await  
Task.Run(() =>
{  
    // Your method to GET the data (don't update the UI here)

    test = "I can set a variable in this context!";

}).ContinueWith(task =>
{
    if (task.Status == TaskStatus.RanToCompletion)
    {
        // update your UI here

        // Again, this is just to show how crossing the context works
        MessageBox.Show(test);
    }
    else
    {
        // update UI with an error message, or display a MessageBox?
    }
}, scheduler);

答案 2 :(得分:0)

你可以试试这个

 private void USB_Utility_Load(object sender, EventArgs e)
{
    lblDisplayStatus.Text = "Detecting Disk Drives...";
}

private void tabUSB_Prep_Enter(object sender, EventArgs e)
{
    tabUSB_Prep.Controls.Clear();
    Task<List<string>> t = new Task<List<string>>(DetectDrivesMethod());
                    t.ContinueWith((result)=>DisplayDrives(result.Result),TaskScheduler.FromCurrentSynchronizationContext);
                    t.Start();
}

您可以调整代码以满足您的要求。在DetectDriveMethod中,您将拥有在后台线程中获取数据的逻辑,并且在继续操作时,您可以拥有更新UI的逻辑。传递同步上下文很重要,否则最终会出现跨线程异常。