如何使用应用程序资源字典进行运行时类型映射

本文关键字:运行时 类型 映射 字典 何使用 应用程序 资源 | 更新日期: 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方法工作

相关文章: