簡體   English   中英

如何使用應用程序ResourceDictionary進行RuntimeType映射

[英]How to use the Application ResourceDictionary to do RuntimeType mapping

我正在嘗試在應用程序的ResourceDictionary中將一個(ViewModel)RuntimeType映射到另一個(View)RuntimeType。 這樣,我的Controller類就可以查找ViewModel對象類,並將其綁定到適當的View類的新實例。 該應用程序被實現為插件的集合,這意味着在編譯時不知道映射。

在我的沙箱應用程序(用於原型設計)中,將映射添加到主Window的資源字典中,如下所示:

<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更改時實例化該類。

但是,當我嘗試將相同的映射放入應用程序的Resource字典中時,會引發異常:

System.Xaml.dll中發生類型為'System.Xaml.XamlObjectWriterException'的第一次機會異常

發生System.Windows.Markup.XamlParseException
HResult = -2146233087消息='“ RuntimeType”對象上缺少鍵值。 行號“ 20”和行位置“ 14”。
來源= PresentationFramework LineNumber = 20 LinePosition = 14
StackTrace:位於System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader,IXamlObjectWriterFactory writerFactory,布爾skipJournaledProperties,對象rootObject,XamlObjectWriterSettings設置,Uri baseUri)
InnerException:System.Xaml.XamlObjectWriterException HResult = -2146233088 Message ='缺少“ RuntimeType”對象上的鍵值。 行號“ 20”和行位置“ 14”。 來源= 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>

關於Window和Application ResourceDictionary對象為何行為不同,如何從異常中查找更多信息或我可能嘗試解決的任何建議。

我的解決方案是向項目添加一個新的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>

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 resource file contains the RuntimeType mappings. -->
            <ResourceDictionary Source="Resources/Mappings.Resources.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

並且(如果有人感興趣),實例化是在DependencyProperty的PropertyChanged事件處理程序中完成的,該事件處理程序綁定了一個將接口暴露給頂級ViewModel基類的對象。

在Mappings.Resources.xaml映射類型中:

  • ConfirmDialogViewModel實現ITopLevelViewModel接口。
  • ConfirmDialog擴展BaseWpfWindow視圖基類。

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方法有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM