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

时间:2014-01-01 05:24:40

标签: c# wpf visual-studio-2013 nsubstitute xaml-designer

我最近发现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>

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

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.";
        }
    }
}

XDependency.cs

namespace DesignTimeNSubstituteIssue.Services
{
    public interface XDependency
    {

    }
}

编译,关闭并重新打开解决方案,然后在设计器中打开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来创建一个变通方法,并手动模拟依赖项,但我很想知道是否有人可以对这个主题有所了解。

1 个答案:

答案 0 :(得分:5)

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