我正在尝试显示一个WPF弹出窗口,它将指示一些进展:
问题是在Thread.Sleep完成之前没有显示弹出窗口,这只是一个例子,在我的程序中我有复杂的IO和DB逻辑需要同步执行,并且需要在弹出窗口中显示进度 .
这是我的示例代码:
private ProgressBar m_ProgressBar;
private void buttonDoWork_Click(object sender, RoutedEventArgs e)
{
var progressPopup = new Popup { PopupAnimation = PopupAnimation.Fade, StaysOpen = true, Height = 150, Width = 260 };
m_ProgressBar = new ProgressBar
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
progressPopup.Child = m_ProgressBar;
progressPopup.IsOpen = true;
Thread.Sleep(5000);
this.m_ProgressBar.Value = 25;
Thread.Sleep(5000);
this.m_ProgressBar.Value = 50;
Thread.Sleep(5000);
this.m_ProgressBar.Value = 75;
Thread.Sleep(5000);
this.m_ProgressBar.Value = 100;
}
Update
问题是阻塞主线程的逻辑需要保留在主线程上,我无能为力 . 有没有办法在单独的线程上运行弹出窗口?
3 回答
使用
更新UI线程上的进度条 .
一般来说,你不应该像这样编织你的代码(UI和逻辑混合)
您可以使用BackgroundWorker或通过引发事件来报告进度的任务 .
EDIT
澄清:暴露从ViewModel /代码更改的数据并引发事件(PropertyChanged),以便您可以将UI绑定到这些值 . 这将允许您保持UI和代码分离 .
我会使用
BackgroundWorker
,其中UI线程和后台线程的拆分非常清楚 .例如,使用它可以签署
ProgressChanged
事件(属于UI线程)并执行任何您想要通知用户后台进程的事情 .问题是WPF要求消息循环旋转,以便它可以调度消息以显示,绘制,响应事件等 . 您必须构造代码以便尽快退出
buttonDoWork_Click
. 如果不这样做,整个UI将冻结 .此外,在单个方法内增加进度值基本上什么都不做 . 从消息循环的角度来看,进度值仅包含单个值... 100 . 这是您在点击事件结束前写入
ProgressBar
的最后一个值 . 这是进度条最终允许刷新自身时所知道的唯一值 .您需要从UI线程中获取该长时间运行的操作 . 这是我的建议 .
使用
Task
类在工作线程上启动操作 .让您的工作线程将进度信息发布到一个简单变量 .
在您选择的时间间隔内通过计时器对进度信息进行UI线程轮询 . 相应地更新
ProgressBar
.