为什么 Dispatcher.Invoke 不触发 UI 更新?
我正在尝试重用 UserControl 并借用一些跟踪进度的逻辑。我会尝试简化事情。 MyWindow.xaml 包含一个 MyUserControl。 MyUserControl 有自己的进度指示器(正在格式化...、正在复制文件...等),我想在 MyWindow 窗体中的某个位置镜像此进度。但是,用户控件有一些我不太明白的逻辑。我读了又读,但我仍然不明白调度程序。以下是用户控件中更新进度的逻辑摘要。
this.Dispatcher.Invoke(DispatcherPriority.Input, (Action)(() =>
{
DAProgressIndicator = InfiniteProgress.AddNewInstanceToControl(StatusGrid, new SolidColorBrush(new Color() { A = 170, R = 128, G = 128, B = 128 }), string.Empty);
DAProgressIndicator.Message = MediaCardAdminRes.ActivatingCard;
ActivateInProgress = true;
}));
我认为我应该聪明地向 MyUserControl 添加一个事件,该事件将在 ActivateInProgress 属性集逻辑中调用。
public bool ActivateInProgress
{
get
{
return _activateInProgress;
}
set
{
_activateInProgress = value;
if (ActivateInProgressHandler != null)
{
ActivateInProgressHandler(value);
}
}
}
我将 MyWindow 构造函数中的 ActivateInProgressHandler 设置为以下方法,该方法设置用于窗口自己的进度指示器的视图模型属性。
private void SetActivation(bool activateInProgress)
{
viewModel.ActivationInProgress = activateInProgress;
}
但是,窗口的进度指示器永远不会改变。所以,我确信 Dispatcher.Invoke 正在做一些我不理解的事情。如果我在 SetActivation 方法中放置一个消息框,线程会阻塞并且窗口的进度指示器会更新。我了解基本的线程,但整个调度程序的事情对我来说是新的。我缺少什么?
更新:它现在似乎正在工作。事实证明,进度更新得太快了,以至于屏幕上根本没有显示出来。但是,我仍然想了解为什么要完成 Dispatcher.Invoke (这是我没有编写的现有代码)。为什么操作内容不与 *.xaml.cs 代码的其余部分一致?
I am trying to reuse a UserControl and also borrow some logic that keeps track of progress. I'll try and simplify things. MyWindow.xaml includes a MyUserControl. MyUserControl has its own progress indicator (Formatting in progress..., Copying files..., etc.) and I'd like to mirror this progress somewhere in the MyWindow form. But, the user control has some logic I don't quite understand. I've read and read but I still don't understand the Dispatcher. Here's a summary of the logic in the user control that updates the progress.
this.Dispatcher.Invoke(DispatcherPriority.Input, (Action)(() =>
{
DAProgressIndicator = InfiniteProgress.AddNewInstanceToControl(StatusGrid, new SolidColorBrush(new Color() { A = 170, R = 128, G = 128, B = 128 }), string.Empty);
DAProgressIndicator.Message = MediaCardAdminRes.ActivatingCard;
ActivateInProgress = true;
}));
I thought I'd be smart and add an event to MyUserControl that would be called in the ActivateInProgress property set logic.
public bool ActivateInProgress
{
get
{
return _activateInProgress;
}
set
{
_activateInProgress = value;
if (ActivateInProgressHandler != null)
{
ActivateInProgressHandler(value);
}
}
}
I'm setting the ActivateInProgressHandler within the MyWindow constructor to the following method that sets the view model property that is used for the window's own progress indicator.
private void SetActivation(bool activateInProgress)
{
viewModel.ActivationInProgress = activateInProgress;
}
However, the window's progress indicator never changes. So, I'm convinced that the Dispatcher.Invoke is doing something that I don't understand. If I put a message box inside the SetActivation method, the thread blocks and the window's progress indicator is updated. I understand basic threads but this whole Dispatcher thing is new to me. What am I missing?
UPDATE: It seems to be working now. It turns out the progress was being updated so fast that it never got shown on the screen. But, I still would like to understand why the Dispatcher.Invoke was done (this was existing code that I didn't write). Why aren't the action contents done in line with the rest of the *.xaml.cs code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的最后一段提到了线程两次,这增加了存在一个或多个后台线程的可能性。但由于您没有提到应用程序中存在哪些线程、它们是如何创建的、它们如何交互等,所以我暂时假设只有一个线程。
如果 UI 线程是唯一的线程,则问题很明显:您的 UI 线程正忙于运行正在进行的任务,并且不花时间呈现更新的 UI。如果这就是问题所在,这可能会解决它:
BeginInvoke 强制所有高于输入优先级的 Dispatcher 操作在当前线程继续之前完成。
Your last paragraph mentions threads twice, which raises the possibility that there are one or more background threads. But since you didn't mention what threads exist in the application, how they are created, how they interact, etc, I'll assume for the moment there is only one thread.
If the UI thread is the only thread, the problem is obvious: Your UI thread is busy running the task in progress, and doesn't take time to render the updated UI. If that's the problem, this will probably fix it:
The BeginInvoke forces all Dispatcher operations above input priority to complete before the current thread continues.
调度程序在队列上工作。因此可能是 UI 线程被阻塞。您通过 Dispatcher 在队列中添加更多工作,但它永远不会被执行,因为 UI 线程正在阻塞。
也许试试这个:
这会将您的工作放在队列中已有的工作之前。因此 UI 线程将完成该工作,然后再次阻塞。
The Dispatcher works on a queue. So it could be that the UI thread is blocking. You add more work in the queue via the Dispatcher but it will never get executed because the UI thread is blocking.
Maybe try this:
This will put your work infront of the work already on the queue. So the UI thread will do the work and then block again.