如何使用应用程序资源字典进行运行时类型映射
本文关键字:运行时 类型 映射 字典 何使用 应用程序 资源 | 更新日期: 2023-09-27 18:15:40
我试图在应用程序的ResourceDictionary中添加从一个(ViewModel) RuntimeType到另一个(View) RuntimeType的映射。这样我的Controller类就可以查找ViewModel对象类并将其绑定到相应View类的新实例。应用程序是作为插件集合实现的,这意味着在编译时不知道映射。
在我的沙盒应用程序(我用于原型)中,映射被添加到主窗口的资源字典中,如下所示:
<Window.Resources>
<!-- This template associates the ConfirmDialog type
with the ConfirmDialogViewModel type. -->
<x:Type TypeName="v:ConfirmDialog" x:Key="{x:Type vm:ConfirmDialogViewModel}" />
</Window.Resources>
这个编译和运行完美,DependencyProperty使用映射来显示ConfirmDialog窗口,查找正确的类,并在附加的ViewModel更改时实例化它。
然而,当我试图将相同的映射放入应用程序的资源字典时,抛出异常:
System.Xaml类型的第一次机会异常。XamlObjectWriterException' occurred in system . xml .dll
System.Windows.Markup。XamlParseException发生
HResult=-2146233087 Message=' RuntimeType'上缺少关键值'对象"。行号为"20",行位为"14"。
Source=PresentationFramework LineNumber=20 LinePosition=14
加:在System.Windows.Markup.WpfXamlLoader。Load(XamlReader, XamlReader, IXamlObjectWriterFactory, writerFactory, Boolean)skipJournaledProperties, Object rootObject, XamlObjectWriterSettings设置,Uri baseUri)
InnerException:System.Xaml.XamlObjectWriterExceptionHResult = -2146233088消息='在'RuntimeType'对象上缺少键值。'行号"20",行位"14"。源=系统。Xaml
资源包含在App.xaml中:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- This resource file contains the DataTemplates. -->
<ResourceDictionary Source="Resources/DataTemplates.Resources.xaml" />
<!-- This resource file contains the Styles. -->
<ResourceDictionary Source="Resources/Styles.Resources.xaml" />
<!-- This section is used for mapping Views to ViewModels. -->
<ResourceDictionary>
<!-- This template associates the ConfirmDialog type
with the ConfirmDialogViewModel type. -->
<x:Type TypeName="v:ConfirmDialog" x:Key="{x:Type vm:ConfirmDialogViewModel}" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
任何关于为什么窗口和应用程序资源字典对象的行为不同的建议,我如何从异常中找到更多的信息,或者我可能试图解决它的事情,我将不胜感激。
我的解决方案是在项目中添加一个新的ResourceDictionary XAML文件,并将其作为MergedDictionary包含。
Mappings.Resources。Xaml(名称空间更改):
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:v="clr-namespace:MyWpfViewNamespace"
xmlns:vm="clr-namespace:MyViewModelNamespace;assembly=MyViewModelAssembly"
>
<!-- This template associates the ConfirmDialog type
with the ConfirmDialogViewModel type. -->
<x:Type TypeName="v:ConfirmDialog" x:Key="{x:Type vm:ConfirmDialogViewModel}" />
</ResourceDictionary>
应用程序。xaml(提取):
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- This resource file contains the DataTemplates. -->
<ResourceDictionary Source="Resources/DataTemplates.Resources.xaml" />
<!-- This resource file contains the Styles. -->
<ResourceDictionary Source="Resources/Styles.Resources.xaml" />
<!-- This resource file contains the RuntimeType mappings. -->
<ResourceDictionary Source="Resources/Mappings.Resources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
并且(如果有人感兴趣的话)实例化是在DependencyProperty的PropertyChanged事件处理程序中完成的,该事件处理程序绑定了一个对象,该对象将接口暴露给顶层ViewModel基类。
在mapping . resources .xaml中映射的类型:
- ConfirmDialogViewModel实现ITopLevelViewModel接口。
- ConfirmDialog扩展了BaseWpfWindow View基类。
ShowModalViewProperty.cs(提取):
public static void ShowModalViewPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var window = d as Window;
ITopLevelViewModel newValue = e.NewValue as ITopLevelViewModel;
if ((null != window) && (null != newValue))
{
// Search the local and Application resources for a mapping
// between the ViewModel type of the new property and a
// View type to use to display it.
Type typeOfViewModel = newValue.GetType();
Type typeOfView = (Type)window.TryFindResource(typeOfViewModel);
if (null == typeOfView)
{
typeOfView = (Type)Application.Current.TryFindResource(typeOfViewModel);
}
// If a concrete type of the correct class is available...
if ((null != typeOfView)&&
(!typeOfView.IsAbstract)&&
(typeOfView.IsSubclassOf(typeof(BaseWpfWindow))))
{
// Create a new window and show it as a (modal) dialog.
BaseWpfWindow dialogWindow = (BaseWpfWindow)
Activator.CreateInstance(typeOfView);
if (null != dialogWindow)
{
dialogWindow.Owner = window;
dialogWindow.DataContext = newValue;
// ModalResult is a Property of ITopLevelViewModel, used to return
// the Window.DialogResult back to the ViewModel object.
newValue.ModalResult = dialogWindow.ShowDialog();
}
}
}
}
我仍然不知道为什么单独的MergedDictionary方法工作