我正在使用实用程序将目录复制到多个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();
}
答案 0 :(得分:0)
老式的方法是使用BackgroundWorker
在getAndDisplayData
中运行阻止工作,然后在启动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();
}
答案 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的逻辑。传递同步上下文很重要,否则最终会出现跨线程异常。