我最近从 Blend 中发现了非常有用的 WPF 组件设计时属性,它(除其他外)允许您仅在设计时设置 DataContext。惊人的!
结合 DesignInstance 属性,您可以设置在设计时自动创建和绑定的类型,允许您使用 Visual Studio 设计器和一些上下文来了解您的 WPF 组件在运行时的实际外观。它真的很好,我希望它没有花我这么长时间才发现。
显然,因为我在这里而不是在程序员的天堂里生活,我在使用这些设计时属性时遇到了问题。
我围绕我的 ViewModel 创建了一个设计时包装器,它有一个无参数的构造函数(因此它可以由设计者创建)。在它的构造函数中,它使用 NSubstitute 来模拟注入到它继承的 ViewModel 中的所有依赖项。
在设计器中使用此设计时类会导致错误,如下所示:
Unable to cast object of type 'Castle.Proxies.XProxy' to type 'X'.
(将 X 替换为我注入的依赖项之一)。
您可以使用以下最少的代码集来重现该问题。
在 VS2013 中创建一个针对 .NET Framework 4.5.1 的 WPF 应用程序(它也可能发生在以前的版本中,我不知道),其中包含以下文件。
查看.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>
视图模型.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; }
}
}
设计时间视图模型.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 并手动模拟依赖项来创建一种解决方法,但我很想看看是否有人可以对这个主题有所了解。