WPF 绑定渲染 Gui 进度

发布于 2024-10-09 16:45:04 字数 270 浏览 0 评论 0原文

我知道这里和那里有几种实现,但我仍然无法“锁定”真正有用的东西...

每当我将某些组件 DataContext 或 ItemsSource 设置为某个大对象时,就会出现“渲染时间冻结 GUI”这使得该应用程序真的很烦人(即使使用虚拟化时)。

我知道我可以迭代该对象并逐一设置项目并显示进度,但我正在寻找其他一些方法,可以让我在 GUI 渲染时显示一些移动指示。我也更喜欢有一些进度条,而不仅仅是让鼠标光标发生变化。

有没有一种好的方法可以实现以下目标?

非常感谢

I know that there are several implementations here and there, but i was still not able to 'lock' on something really useful...

Whenever i set some component DataContext or ItemsSource to some big object, there is this 'render time frozen GUI' which make the app real annoying (even when using Virtualization).

I know i can iterate the object and set the items one by one and show progress, but i am looking for some other approach which can let me show some moving indication while GUI is rendering. I also prefer to have some progress bar and not only make the mouse cursor change.

Is there a decent way to achieve the followings?

Many Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

画尸师 2024-10-16 16:45:04

Zamboni 示例是一个非常好的示例,但仍然没有解决冻结 GUI 问题

如前所述,当前没有简单的方法可以在 GUI 忙于渲染时让某些内容“活动”来更新 GUI 控件。

我目前发现一些事件在 gui 渲染时“活跃且活跃”,尽管在不需要时应该将其关闭,因为它每秒可以触发 60 次。

CompositionTarget.Rendering += ReportRenderProgress;

然后,您可以以任何您喜欢的方式实现 ReportRenderProgress() 来指示进度条更新。目前,我在 WPF 中没有看到任何更好的解决方案可以在渲染时更新进度指示,因此我将其标记为答案。

Zamboni example is a very good one, but still does not solve the frozen GUI problem.

As mentioned, there is no currently simple way of having something 'alive' to update a gui control while GUI is busy rendering.

I currently found some event that is 'alive and kicking' while gui is rendering, althogh it should be turned off when not needed as it can fire something like 60 times per second.

CompositionTarget.Rendering += ReportRenderProgress;

You can then implement ReportRenderProgress() anyway you like to signal you progress bar to update. Currently, i dont see any better solution available in WPF to update a progress indication while rendering so i am marking this as the answer.

ゝ杯具 2024-10-16 16:45:04

这其实是一个问题。您正在使用 GUI 线程来填充数据(从对象结构到 GUI)。 GUI 线程既需要读取 Windows 消息队列(防止应用程序冻结,允许应用程序移动/响应),又需要对 GUI 进行任何更新。

一种解决方案可能是在绑定后慢慢填充对象结构。这必须从 GUI 线程完成,因此您可以添加 DoEvents() 和/或一些百分比指示器+强制刷新以使应用程序看起来活跃。

我很想听听是否有人有更好的解决方案。

This is actually a problem. You are using the GUI thread to fill the data (from object structure into GUI). The GUI thread is required both to read Windows message queue (prevent app from freezing, allow app to be moved/respond) and it is required to do any updates to the GUI.

One solution could be to slowly fill the the object structure after binding. This would have to be done from the GUI thread, so you could add DoEvents() and/or some percent indicator+forced refresh to make application seem alive.

I am interested to hear if anyone has a better solution though.

匿名。 2024-10-16 16:45:04

BackgroundWorker 拥有您所需的一切。

编辑

在 WPF 中,调度程序被自动用来调用跨线程方法调用。
查看 MSDN 杂志中的使用 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();
   }
}

BackgroundWorker has everything you need.

EDIT

In WPF the Dispatcher is being employed automatically to invoke cross-thread method calls.
Check out Build More Responsive Apps With The Dispatcher in MSDN magazine.

I also put together some code fragments from a ViewModel that shows a BackgroundWorker updating a progress bar.

<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();
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文