C# 如何使用应用程序ResourceDictionary进行运行时类型映射

C# 如何使用应用程序ResourceDictionary进行运行时类型映射,c#,wpf,xaml,C#,Wpf,Xaml,我试图在应用程序的ResourceDictionary中添加从一个(ViewModel)RuntimeType到另一个(View)RuntimeType的映射。这样,我的控制器类就可以查找ViewModel对象类,并将其绑定到相应视图类的新实例。应用程序被实现为插件的集合,这意味着在编译时映射是未知的 在我的沙盒应用程序(用于原型制作)中,映射被添加到主窗口的资源字典中,如下所示: <Window.Resources> <!-- This template associ

我试图在应用程序的ResourceDictionary中添加从一个(ViewModel)RuntimeType到另一个(View)RuntimeType的映射。这样,我的控制器类就可以查找ViewModel对象类,并将其绑定到相应视图类的新实例。应用程序被实现为插件的集合,这意味着在编译时映射是未知的

在我的沙盒应用程序(用于原型制作)中,映射被添加到主窗口的资源字典中,如下所示:

<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.dll中首次出现类型为“System.Xaml.XamlObjectWriterException”的异常

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)
内部异常: System.Xaml.XamlObjectWriterException HResult=-2146233088 Message='RuntimeType'对象缺少键值。'行号'20'和行位置'14'。 Source=System.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对象行为不同的原因、我如何从异常中找到更多信息或我可能尝试解决它的问题的建议都将不胜感激。

我的解决方案是向项目中添加一个新的ResourceDictionary XAML文件,并将其作为合并词典

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>
<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>
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();
            }
        }
    }
}