在我的程序中,我使用一个单独的线程来读取外部文件并将数据传送到我的程序。我正在尝试在该线程运行时在UI线程上运行ProgressBar
,以便向用户提供反馈。截至目前,我有一个ProgressBar
打开,但没有关闭,因为我不知道如何告诉它子线程已经结束。我已经在ProgressBars上阅读了本教程,并且应该注意我的线程没有使用BackgroundWorker
。而不是这个,我只是使用System.Threading.Thread
。如果这是一个问题,请告诉我。
打开包含OpenFile()
的Window的ProgressBar
方法,并启动将执行打开文件工作的线程:
public void OpenFile()
{
//Open Progress Bar Window
LoadingWindow = new LoadingScreen(App.MainWindowViewModel.LoadScreen);
LoadingWindow.Show();
App.MainWindowViewModel.LoadScreen.IsIndeterminate = true;
FILE_INPUT = true; //bool that Signifies that the background thread is running
//Create Thread -- run routines in thread
var openFileThread = new Thread(() => openDefault(txtFile)); //Passes the file
openFileThread.Start(); //Start File open thread
}
//This thread reads in the file and transfers the data to the program
private void openDefault(StreamReader txtFile)
{
//Gathers info from file and changes program accordingly
FILE_INPUT = false; //background thread is no longer running
}
截至目前,我没有ProgressBar
的增量方法,因为我想确保在处理类似的技术细节之前我能够正常工作。无论如何,我的问题是......在我的程序中如何以及在何处知道后台线程已经完成并且LoadingWindow
(ProgressBar
)可以关闭?
更多代码可帮助您了解我的计划流程:
主窗口代码背后:
private void OpenFile_Click(object sender, RoutedEventArgs e)
{
OpenFile(); //calls to the method that launches the new thread and the window with the Progress Bar
//Wait until background Thread is complete
while (ViewModel.FILE_INPUT == true) { }
//After thread has stopped running, close the window (DOES NOT WORK)
ViewModel.LoadingWindow.Close(); // -- Close Prog Bar
}
最终解决方案:
//In OpenFile() method
LoadingWindow = new LoadingScreen(App.MainWindowViewModel.LoadScreen); //Open Progress Bar Window
LoadingWindow.Show();
App.MainWindowViewModel.LoadScreen.IsIndeterminate = true;
FILE_INPUT = true; //A file is being inputted*
Dispatcher UIDispatcher = Dispatcher.CurrentDispatcher;
Task.Factory.StartNew(() =>
{
openDefault(txtFile); //Passes the file
//After thread has stopped running, close the Loading Window
UIDispatcher.Invoke((Action)(() => LoadingWindow.Close())); //Close progress bar
});
答案 0 :(得分:1)
如果没有完整的代码示例,很难提供完整的答案。根据您实际执行文件I / O和管理ProgressBar
的方式,您可能还需要进行其他更改以改进代码。但为了解决眼前的问题,我建议您利用async
/ await
模式:
public async Task OpenFile()
{
//Open Progress Bar Window
LoadingWindow = new LoadingScreen(App.MainWindowViewModel.LoadScreen);
LoadingWindow.Show();
App.MainWindowViewModel.LoadScreen.IsIndeterminate = true;
FILE_INPUT = true; //bool that Signifies that the background thread is running
//Create Thread -- run routines in thread
await Task.Run(() => openDefault(txtFile)); //Passes the file
}
private async void OpenFile_Click(object sender, RoutedEventArgs e)
{
await OpenFile(); //calls to the method that launches the new thread and the window with the Progress Bar
//After thread has stopped running, close the window
ViewModel.LoadingWindow.Close(); // -- Close Prog Bar
}
这样可以避免在操作工作时导致UI冻结,同时允许以简单直接的方式编写代码。
通过上述更改,您可以完全摆脱FILE_INPUT
变量(不清楚您可能正在使用它的其他内容,但它可能不是其他内容。)
请注意,OpenFile()
方法已更改为返回Task
。这是没有实际返回值的async
方法的标准。对OpenFile_Click()
方法进行相同的更改 ,但作为事件处理程序,通常需要返回void
。两种语法都是合法的,但前者在可能的情况下是首选,因此可以访问Task
对象(用于异常处理,完成等)。
编辑,对于那些没有.NET 4.5并且无法安装必要组件以支持async
/ await
(这只是编译时更改)的人,这里是一个可以在.NET 4.0中运行的示例:
public void OpenFile()
{
//Open Progress Bar Window
LoadingWindow = new LoadingScreen(App.MainWindowViewModel.LoadScreen);
LoadingWindow.Show();
App.MainWindowViewModel.LoadScreen.IsIndeterminate = true;
FILE_INPUT = true; //bool that Signifies that the background thread is running
//Create Thread -- run routines in thread
Task.Factory.StartNew(() =>
{
openDefault(txtFile); //Passes the file
//After thread has stopped running, close the window
Dispatcher.Invoke((Action)(() => ViewModel.LoadingWindow.Close())); // -- Close Prog Bar
});
}
private void OpenFile_Click(object sender, RoutedEventArgs e)
{
//calls to the method that launches the new thread and the window with the Progress Bar
OpenFile();
}
(这实际上在语义上与async
/ await
实现略有不同,因为我只是将窗口关闭操作放在该任务中,而不是为第一个任务创建延续。但它应该有相同的净结果。)