Show.Busy() 和 Show.NotBusy() 的 Caliburn 错误
我有一个使用 Show.Dialog() 显示的对话框,并且在附加到视图的 Loaded 事件的方法中具有以下步骤:
- Show.Busy()
- 可能长时间运行的 Web 请求(这里有一个自定义异步 IResult)
- 如果通过 Show.MessageBox()
- Show.NotBusy()
出现错误,则弹出窗口我发现,如果您在步骤 2 中关闭视图并需要一段时间,然后重新打开,则新视图上的步骤 1 的繁忙指示器不会出现显示。
所以一开始,我认为这是我的错,并设置了一个简单的机制来在视图关闭时取消步骤 4。但运气不佳...
从看起来来看,步骤 1 中的 Show.Busy() 正在尝试与已关闭的视图进行交互。这是 Caliburn 中的错误吗?
我的 ViewModel 是单例,因此这也可能归因于我认为的问题。为了进行测试,我切换到 IsBusy 布尔属性,问题就消失了。然而,这对我的整个申请来说是一个很大的改变。
关于任何解决方法的想法?或者 Caliburn 的一个人可以帮我吗?我正在使用完整版 Caliburn 的最新版本。
更新:
我尝试了 Marco 的解决方法,导入了 IBusyService 并在我的 ViewModel 中执行了此操作:
public override void TryClose(bool? dialogResult)
{
_busyService.MarkAsNotBusy(this);
base.TryClose(dialogResult);
}
但它似乎没有帮助。如果我做一个简单的重现会有帮助吗?
更新#2:
我继续进行复制,因为很多时候都会发现问题。
事实证明,这与我必须直接调用 IWindowManager 有关。我的应用程序部分是带有插件架构的 WinForms,并且我们使用了几个基于 Caliburn 的插件。
以下是导致问题的代码示例:
if (_child.IsActive)
{
_child.BringToFront();
}
else
{
_manager.ShowWindow(_child);
}
这是 WinForms NotifyIcon MenuItem 的单击事件处理程序中的代码。
_child 是一个 Screen,其中 BringToFront() 调用底层 View 的 Activate 方法(当然是通过服务)。 _manager 是 IWindowManager。
如果您直接运行 Caliburn,Show.Dialog() 不会导致问题。
关于解决方法有什么想法吗?我不确定这是否是 Caliburn 问题,但可能只是由直接使用 IWindowManager 引起的。
I have a dialog that is displayed with Show.Dialog(), and has these steps in a method attached to the Loaded event of the view:
- Show.Busy()
- Possible long-running web request (I have a custom asynchronous IResult here)
- Popup if error via Show.MessageBox()
- Show.NotBusy()
I have found if you close my view at step 2 when it is taking a while, and re-open, the busy indicator for step 1 on the new view isn't displayed.
So at first, I thought it was my fault, and put a simple mechanism to cancel step 4 if the view was closed. But no luck...
From what it looks like, Show.Busy() in step 1 is attempting to interact with the view that was already closed. Is this a bug in Caliburn?
My ViewModel is a singleton, so that could also attribute to the issue I suppose. For a test, I switched to a IsBusy boolean property and the problem goes away. However this would be a large change to make throughout my entire application.
Thoughts on any workarounds? Or can one of the Caliburn guys help me out here? I am using the latest release of the full version of Caliburn.
UPDATE:
I tried Marco's workaround, imported IBusyService and did this in my ViewModel:
public override void TryClose(bool? dialogResult)
{
_busyService.MarkAsNotBusy(this);
base.TryClose(dialogResult);
}
But it doesn't seem to help. Would it help if I made a simple repro?
UPDATE #2:
I went ahead and made a repro, since that alot of the time will identify issues.
Turns out, it is related to me having to directly call the IWindowManager. My application is partially WinForms with a plugin architecture, and we use several Caliburn-based plugins.
Here is an example of the code causing the issue:
if (_child.IsActive)
{
_child.BringToFront();
}
else
{
_manager.ShowWindow(_child);
}
This is in the click event handler of a WinForms NotifyIcon MenuItem.
_child is a Screen, where BringToFront() is calls the Activate method of the underlying View (by a service, of course). _manager is the IWindowManager.
If you are running straight Caliburn, Show.Dialog() does not cause the issue.
Any ideas on a workaround? I'm not sure this is a Caliburn issue anymore, but possibly just caused by the direct use of IWindowManager.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
繁忙的虚拟机(以及相关的繁忙指示器 UIElement)保存在 DefaultBusyService 的注册表中。
我的猜测是,当虚拟机在被标记为不忙之前关闭时,相关条目将保留在注册表中,从而防止该服务在再次显示同一虚拟机实例时在较新的 UIElement 上工作。
不过,我应该多调查一下;我提交了一个问题:http://caliburn.codeplex.com/workitem/8395
作为临时解决方法是,您可以尝试在 VM 关闭阶段调用 IBusyService.MarkAsNotBusy,并传递 VM 本身的引用。
The busy VMs (and related busy indicator UIElement) are kept in a registry into DefaultBusyService.
My guess is that when the VM is closed before being marked as not busy, the related entry is kept in the registry, thus preventing the service to work on the newer UIElement when the same VM instance is shown again.
I should investigate a little more, though; I filed an issue: http://caliburn.codeplex.com/workitem/8395
As a temporary workaround you might try calling
IBusyService.MarkAsNotBusy
on the VM shutdown phase, passing the reference of the VM itself.