我知道这里和那里有几个实现,但我仍然无法“锁定”真正有用的东西......
每当我将一些组件DataContext或ItemsSource设置为某个大对象时,就会出现“渲染时冻结的GUI”,这会让应用程序变得烦人(即使使用虚拟化)。
我知道我可以迭代对象并逐个设置项目并显示进度,但我正在寻找一些其他方法,可以让我在GUI渲染时显示一些移动指示。我也喜欢有一些进度条,不仅让鼠标光标改变。
有没有一种可行的方法来实现以下目标?
非常感谢
答案 0 :(得分:3)
Zamboni示例非常好,但仍然无法解决冻结的GUI问题。
如上所述,当GUI忙于渲染时,目前还没有简单的方法可以更新gui控件。
我目前发现了一些'活着并且踢'而 gui正在呈现的事件,但是在不需要的时候它应该被关闭,因为它可以每秒发射60次。
CompositionTarget.Rendering += ReportRenderProgress;
然后,您可以实施ReportRenderProgress()
,以表示您要更新进度条。目前,我没有在WPF中看到任何更好的解决方案,以便在渲染时更新进度指示,因此我将此标记为答案。
答案 1 :(得分:2)
这实际上是一个问题。您正在使用GUI线程来填充数据(从对象结构到GUI)。 GUI线程既需要读取Windows消息队列(防止应用程序冻结,允许移动/响应应用程序),也需要对GUI进行任何更新。
一种解决方案可能是在绑定后缓慢填充对象结构。这必须从GUI线程完成,因此您可以添加DoEvents()和/或一些百分比指示符+强制刷新,以使应用程序看起来活着。
我很想知道是否有人有更好的解决方案。
答案 2 :(得分:2)
BackgroundWorker拥有您需要的一切。
修改强>
在WPF中,Dispatcher被自动用于调用跨线程方法调用。 查看MSDN杂志中的Build More Responsive Apps With The Dispatcher。
我还将来自ViewModel的一些代码片段放在一起,显示了BackgroundWorker更新进度条。
<ProgressBar
VerticalContentAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Minimum="0" Maximum="100"
Value="{Binding Path=BarPosition, Mode=TwoWay}"/>
// configure the background worker...
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.WorkerSupportsCancellation = true;
_backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
// control progress bar position
private int _barPosition = 0;
public int BarPosition
{
get { return _barPosition; }
set
{
_barPosition = value;
OnPropertyChanged("BarPosition");
}
}
// long operation
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
if (bw != null)
{
int pos;
for (int i = 0; i < 100; ++i
{
// report progress here for our long running operation..
pos = i/100;
bw.ReportProgress(pos);
Thread.Sleep(1000); // fake long operation
}
}
}
// report progress,,,
void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
if (bw != null)
{
BarPosition = e.ProgressPercentage;
}
}
// reset scroll bar position
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
if (bw != null)
{
BarPosition = 0;
// Forcing the CommandManager to raise the RequerySuggested event to refresh UI...
CommandManager.InvalidateRequerySuggested();
}
}