XAML 设计时执行了哪些代码?在 Visual Studio 和 Blend 中。

5
作为背景,我正在使用一个Windows Store应用程序和Windows Phone 8应用程序共享单个ViewModel(PCL)。
我正在使用MVVMLight和NInject / Common Service Locator来实例化视图模型和服务。这很不错,并且给了我非常好的松散耦合,非常适合测试等等。
然而,获得设计时数据支持(通过切换不同的NInject模块等)是一个完全的黑盒子,虽然我现在已经让它工作了,但我对它并不是很满意,它主要是通过试错来实现的。
我使用的是标准做法,即拥有一个ViewModelLocator(作为应用程序资源实例化),它从Service Locator中提取View Model。这总是被执行。
问题是,我无法确定我的代码有多少实际上被设计时编辑器执行。因此,为了确保NInject已初始化并且CSL已连接到NInject,我必须在ViewModelLocator上有一个静态构造函数,该函数调用我的App类启动NInject。
这似乎不对劲。所以,我想知道这方面的最佳实践是什么,是否有任何关于应用程序哪些部分“启动”而显示在设计时的文档/保证,以及这是否在Windows Store应用程序和Windows Phone 8应用程序之间有所不同。
ViewModelLocator.cs(片段)
public class ViewModelLocator
{
    static ViewModelLocator()
    {
        System.Diagnostics.Debug.WriteLine("VML Start");
        var servicelocator = new NinjectServiceLocator(App.Kernel);
        ServiceLocator.SetLocatorProvider(() => servicelocator);
        System.Diagnostics.Debug.WriteLine("VML End");
    }

    public AppViewModel AppViewModel
    {
        get { return ServiceLocator.Current.GetInstance<AppViewModel>(); }
    }

    public MainViewModel MainViewModel
    {
        get { return ServiceLocator.Current.GetInstance<MainViewModel>(); }
    } 
}

App.xaml.cs (snippet)

partial class App : Application
{
    public static StandardKernel Kernel { private set; get; }

    static App()
    {
        // Register dependencies & hook the service locator to use NInject under the hood
        var servicemodule = ViewModelBase.IsInDesignModeStatic ? (NinjectModule)new DesignTimeModule() : new RunTimeModule();
        var viewmodelmodule = new ViewModelModule();
        App.Kernel = new StandardKernel(servicemodule, viewmodelmodule);
    }
}

App.xaml(代码片段)

<?xml version="1.0" encoding="utf-8"?>
<Application RequestedTheme="Dark"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="KieranBenton.LeaveNow.App.App"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:app="using:KieranBenton.LeaveNow.App"
             xmlns:dependencies="using:KieranBenton.LeaveNow.App.Dependencies"
             mc:Ignorable="d">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                ...
            </ResourceDictionary.MergedDictionaries>
            <dependencies:ViewModelLocator x:Key="ViewModelLocator"
                                           d:IsDataSource="True" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

Main.xaml

<tcdcontrols:LayoutAwarePage x:Name="pageRoot"
                             x:Class="KieranBenton.LeaveNow.App.Pages.Main"
                                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                             xmlns:tcdcontrols="using:TCD.Controls"
                             xmlns:vm="using:KieranBenton.LeaveNow.ViewModel"
                             mc:Ignorable="d"
                             DataContext="{Binding MainViewModel, Source={StaticResource ViewModelLocator}}">
    <Page.Resources>
        <!-- Collection of grouped items displayed by this page, bound to a subset of the complete item list because items in groups cannot be virtualized -->
        <!-- NOTE: Ridiculous lengths to get this working - see http://www.ralbu.com/post/2012/11/18/Building-WinRT-Windows-8-Grouped-items-using-MVVMLight.aspx -->
        <CollectionViewSource x:Name="groupedItemsViewSource"
                              Source="{Binding Journeys}"
                              d:Source="{Binding Journeys, Source={d:DesignInstance Type=vm:Main, IsDesignTimeCreatable=True}}"
                              IsSourceGrouped="true"
                              ItemsPath="Routes" />
    </Page.Resources>
1个回答

5
设计时编辑器应该只实例化您正在编辑的页面并执行在此期间调用的任何代码:
- 它解析和实例化其中的所有内容,包括您定义的任何资源 - 它执行页面构造函数 - 任何静态构造函数将被调用,并且一旦“触摸”该类(无论是其静态成员还是实例化它),静态字段将被初始化
您没有说明要如何实例化您的 ViewModelLocator 并在尝试使设计器工作之前初始化 Ninject。因此,很难提出建议如何修复它。
作为设计时数据的一般建议,我建议您坚持使用 DesignInstance markup,它适用于 Windows Store 应用程序和 Windows Phone 8。您只需要向您的 Page 标记添加设计时 DataContext 即可:
<Page xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      d:DataContext="{d:DesignInstance viewModels:PageViewModel, IsDesignTimeCreatable=True}">

我正在使用MVVMLight最佳实践来实例化ViewModelLocator,通过在App资源中创建一个实例(我会在一分钟内更新问题)。我希望能够在App类的某个地方设置NInject和CSL - 因为目前我必须在ViewModelLocator内部进行设置,因为App类似乎没有被实例化。 - Kieran Benton
已更新 - 您应该能够从Main.xaml -> Application.Resources.ViewModelLocator -> ViewModelLocator.MainViewModel看到绑定。我不明白的是如何访问Application.Resources,但构造函数似乎没有被访问。 - Kieran Benton
@KieranBenton 是的,据我所知,App.xaml仅被引用为资源,该类未被实例化。你的另一种方法是手动实例化设计工具所需的类(使用DesignerProperties.IsInDesignTool)。另一个方法是直接在XAML中实例化设计时视图模型,就像我已经建议的那样。你真的需要在设计时使用DI吗? - Damir Arh
不需要 DI - 只是希望一切尽可能可预测 :) 这些内容有官方文档吗,还是你通过经验了解的?谢谢。 - Kieran Benton
@KieranBenton 我还没有找到关于设计时执行的代码的任何文档。目前只是个人经验。不过我很乐意去了解一下。 - Damir Arh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接