我正在尝试在WPF + PRISM + MVVM应用程序中实现对话窗口。现在我设法创建了示例服务,每个模块都能够使用这个服务在窗口中显示任何视图,但问题是非常不寻常的,无法使其工作。
这是窗口服务的合同。
public interface IUiDialogueService : IDisposable
{
void Show<TView>(TView view) where TView : IViewModel;
}
public class UiDialogueService : IUiDialogueService, IDisposable
{
private Window _dialogueWindow;
#region Implementation of IUiDialogueService
public void Show<TView>(TView view) where TView : IViewModel
{
_dialogueWindow = new Window
{
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.NoResize,
ShowInTaskbar = false,
Content = view.View
};
_dialogueWindow.ShowDialog();
_dialogueWindow = null;
}
}
以下是我从模块访问窗口服务的方法。
private void OnStartWizard()
{
_dialogueService.Show(ServiceLocator.Current
.GetInstance<IOrgManagementOrganizatioSetupViewViewModel>());
}
当我第一次打开窗口时一切正常但在我关闭它并打开窗口内的相同或其他视图后我恢复了异常
指定的元素已经是另一个元素的逻辑子元素。首先断开它。
以下代码抛出此异常。
_dialogueWindow = new Window
{
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.NoResize,
ShowInTaskbar = false,
Content = view.View
};
有没有人可以解释这里发生了什么问题?有没有更好的方法来获得MVVM架构中的子(对话)窗口?
答案 0 :(得分:3)
尝试在Show
的最后一行之前添加以下代码:
_dialogueWindow.Content = null;
Show
现在看起来应该是这样的:
public void Show<TView>(TView view) where TView : IViewModel
{
_dialogueWindow = new Window
{
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.NoResize,
ShowInTaskbar = false,
Content = view.View
};
_dialogueWindow.ShowDialog();
_dialogueWindow.Content = null;
_dialogueWindow = null;
}
答案 1 :(得分:1)
WPF中的每个元素只能属于一个父元素。即使元素未显示(或再显示),父子关系仍然存在。如果要为元素提供新父元素,则需要先从旧父元素中删除它。
在您的情况下,在Show()
中,您将窗口的内容设置为您的视图。即使在显示该窗口之后,该视图仍然是该窗口的子项。如果您现在尝试在不同的窗口中显示相同的视图,那么您将获得该异常。
最好的方法是从Window中删除视图(在Daniel Hilgarth的回答中描述)。或者,您可以检查视图是否已有父级,并首先从该父级手动删除它。