无法将类型为"Castle.Proxies.XProxy"的对象转换为在WPF设计器中键入"X"

Tod*_*les 6 c# wpf xaml-designer nsubstitute visual-studio-2013

我最近发现了Blend for WPF组件非常有用的设计时属性,其中(除其他外)允许您仅在设计时设置DataContext.真棒!

结合DesignInstance属性,您可以设置在设计时自动创建和绑定的类型,允许您使用Visual Studio Designer以及WPF组件在运行时实际看起来的内容.它非常好,我希望它没有花太多时间去发现.

显然,因为我在这里而不是在程序员天堂里生活,所以在使用这些设计时属性时我遇到了一个问题.

我在一个我的ViewModels周围创建了一个设计时包装器,它有一个无参数构造函数(所以它可以由设计者创建).在它的构造函数中,它使用NSubstitute来模拟注入它继承的ViewModel的所有依赖项.

在设计器中使用此设计时间类会导致错误,如下所示:

Unable to cast object of type 'Castle.Proxies.XProxy' to type 'X'.

(将X替换为我注入的依赖项之一).

您可以使用以下最小代码集来重现该问题.

在VS2013中创建一个针对.NET Framework 4.5.1的WPF应用程序(在以前的版本中也可能发生,我不知道),其中包含以下文件.

View.xaml

<Page 
    x:Class="DesignTimeNSubstituteIssue.Views.View"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:DesignTimeNSubstituteIssue_Views_DesignTime="clr-namespace:DesignTimeNSubstituteIssue.Views.DesignTime"
    mc:Ignorable="d" 
    d:DataContext="{d:DesignInstance Type=DesignTimeNSubstituteIssue_Views_DesignTime:DesignTimeViewModel, IsDesignTimeCreatable=True}">
    <Grid>
        <TextBlock Text="{Binding Message, FallbackValue=Design_Time_Message_Failed_Using_Fallback}"/>
    </Grid>
</Page>
Run Code Online (Sandbox Code Playgroud)

ViewModel.cs

using DesignTimeNSubstituteIssue.Services;

namespace DesignTimeNSubstituteIssue.ViewModels
{
    public class ViewModel
    {
        public ViewModel(XDependency dependency)
        {
            _Dependency = dependency;
        }

        private readonly XDependency _Dependency;
        public string Message { get; protected set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

DesignTimeViewModel.cs

using DesignTimeNSubstituteIssue.Services;
using DesignTimeNSubstituteIssue.ViewModels;
using NSubstitute;

namespace DesignTimeNSubstituteIssue.Views.DesignTime
{
    public class DesignTimeViewModel : ViewModel
    {
        public DesignTimeViewModel()
            : base(Substitute.For<XDependency>())
        {
            Message = "This is a Design Time message.";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

XDependency.cs

namespace DesignTimeNSubstituteIssue.Services
{
    public interface XDependency
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

编译,关闭并重新打开解决方案,然后在设计器中打开View.xaml.它会工作得很好.然后,关闭设计器,重建解决方案并再次在设计器中打开View.xaml,您将收到以下错误:

Unable to cast object of type 'Castle.Proxies.XDependencyProxy_1' to type 'DesignTimeNSubstituteIssue.Services.XDependency'.

发生此错误时,设计器停止使用指定的DesignTimeViewModel,并返回到根本没有DataContext.

解决此问题的唯一方法是关闭并重新打开解决方案.

我怀疑我知道发生了什么,但我不知道为什么会发生这种情况或如何解决它.

我认为在第一次编译时,设计者正在获取对程序集的引用并对其进行缓存.当第二次编译发生时,程序集被重建并且大部分是相同的,但NSubstitute代理重新生成了一个新的后缀(比如Castle.Proxies.XDependencyProxy_2或某些东西),它不在第一个程序集中,所以设计者不知道那个代理实际上实现了XDependency接口.这纯粹是我猜想的猜测.

我可以通过不使用NSubstitute来创建一个解决方法,并手动模拟依赖项,但我很想知道是否有人可以阐明这个主题.

Tod*_*les 5

看起来我的原始项目和最小复制项目都没有正确地对程序集进行版本化,这意味着设计人员不知道它需要重新加载程序集(因为新程序与旧程序版本完全相同).更改程序集版本以包含自动生成的版本号似乎可以解决问题.