用例
我正在开发一个C#中的小应用程序,该应用程序由另一个应用程序调用以从Internet检索数据。它作为一个进程独立运行,但几乎所有与它的交互都由调用应用程序管理。因此它没有GUI。但是,我想在某些数据检索过程中使用WPF添加进度条,这可能需要一分钟。很容易估计完成了多少工作以及剩下多少工作量,因此我找到了一个合适的进度条。
完成研究
在阅读Albahari的pdf大部分线程(http://www.albahari.info/threading/threading.pdf)之后,我对线程有了一个很好的理解。在此问题上,我还阅读了很多关于SO和MSDN的帖子。大多数帖子建议使用后台工作人员进行耗时的数据检索,同时将GUI保留在主线程中,并因此建议使用后台工作者的解决方案。在这种情况下,这感觉很尴尬,主要任务是数据检索,而不是GUI交互。
我花了一些时间试图理解不同的教程和论坛帖子,同时试图使他们符合我的问题,但我没有成功,现在我几乎回到原点。基本上我想最终得到以下两个类:
ProgressBarWindow
public partial class ProgressBarWindow : Window
{
public ProgressBarWindow()
{
InitializeComponent();
}
public void setValue(int value)
{
// This function should be available from the main thread
}
}
查询器
Public class Querier
{
public List<Item> getItems()
{
// call ProgressBarWindow.setValue(0);
...
// call ProgressBarWindow.setValue(100);
// call ProgressBarWindow.Close();
}
}
我的理解是UI必须在单个线程下运行,因此我的ProgressBarWindow
对象无法在新线程中实例化,同时可用于主线程(类型)。
Dispatcher.BeginInvoke似乎是我的救世主,但到目前为止,我还未能弄清楚Querier
课程应该进入什么以及ProgressBarWindow
课程中要做什么。如何让两个线程与ProgressBarWindow的同一个实例进行交互?
请询问您是否需要更多详情,我会尽力澄清。
答案 0 :(得分:1)
您可以使用Progress
类使用长时间运行操作的当前进度来更新UI。
首先在您的用户界面中创建Progress
的实例:
Progress<int> progress = new Progress<int>(currentProgress =>
{
progressBar.Value = currentProgress;
//todo do other stuff
});
然后将其传递给长时间运行的过程:
public List<Item> getItems(IProgress<int> progress)
{
progress.Report(0);
//todo do something
progress.Report(100);
}
答案 1 :(得分:0)
这是我通常使用的通用函数:
public static void Invoke(this UIElement element,Action action)
{
element.Dispatcher.Invoke(action, null);
}
要使用它,只需致电:
this.Invoke(() => ProgressBarWindow.SetValue(0));
因此,在getItems()函数中,你会得到以下内容:
public List<Item> getItems()
{
ProgressBarWindow wnd;
MainWindow.Invoke(() => wnd = new ProgressBarWindow())
MainWindow.Invoke(() => wnd.SetValue(0))
...
MainWindow.Invoke(() => wnd.SetValue(100))
MainWindow.Invoke(() => wnd.Close())
}
确保总是有办法到达主窗口的任何东西(从App.xml或App.Run(...)运行的那个。然后你可以通过它发出任何GUI动作(即使你必须创建一个新的Loader窗口,例如,只要它在主线程中完成)
答案 2 :(得分:0)
的App.xaml
public partial class App : Application
{
private void Application_Startup_1(object sender, StartupEventArgs e)
{
Task.Factory.StartNew<List<int>>(() => Querier.GetItems());
}
}
ProgressBarWindow.xaml.cs
public partial class ProgressWindow : Window
{
public ProgressWindow()
{
InitializeComponent();
Querier.Start +=()=> Visibility = Visibility.Visible;
Querier.Stop += () => Visibility = Visibility.Collapsed;
Querier.ReportProgress +=OnReportProgress;
}
public void OnReportProgress(int value)
{
txtBox.Text = value.ToString();
}
}
ProgressBarWindow.xaml
<Grid>
<TextBox x:Name="txtBox"></TextBox>
</Grid>
查询器
public class Querier
{
public static event Action Start;
public static event Action Stop;
public static event Action<int> ReportProgress;
public static List<int> GetItems()
{
if (Start != null)
App.Current.Dispatcher.BeginInvoke(Start,null);
for (int index = 0; index <= 10; index++)
{
Thread.Sleep(200);
if (ReportProgress != null)
App.Current.Dispatcher.BeginInvoke(ReportProgress, index*10);
}
if (Stop != null)
App.Current.Dispatcher.BeginInvoke(Stop, null);
return Enumerable.Range(1, 100).ToList();
}
}
我只想提出一个想法,希望这会有所帮助。