我将UI绑定到接口(由几个演示者实现,无法从UI程序集访问)。
我非常喜欢设计师中的D:DesignInstance,因为它(有点)使用R#强力键入xaml。
可悲的是,d:DesignInstance不支持接口类型:“无法创建接口实例。”
我想到的第一件事是:好的,没问题,让我们创建一个自定义标记扩展,它将System.Type作为参数,以及哪个ProvideValue方法返回它的假实例(此接口的虚拟实现,由动态生成IL发射。)
这很有效,绑定在设计时被解析(我可以在设计面板中看到,因为我的标记扩展用lorem-ipsum填充了对象属性)
但是最好的R#功能不起作用:Resharper无法识别datacontext类型,只是在“object”类型的数据上下文中给出了“无法解析属性'{0}”的消息/ p>
有人知道如何解决这个问题吗?
(允许我让R#了解接口datacontext类型的任何替代方案都会很棒)
谢谢!
ps: 我还尝试创建另一个标记扩展,它返回生成的运行时类型,以便将其提供给DesignInstance:“{d:DesignInstance Type = {utilsUi :InstanceType commons:User}}“=>给出错误“类型'对象InstanceType'无法转换为'System.Type'类型” ......似乎DesignInstance不支持内部标记扩展:(
答案 0 :(得分:21)
我发现如何克服这种不合逻辑的Visual Studio XAML设计器错误。
而不是
xyzzy/plugh.h
你可以写
<SomeControl d:DataContext={d:DesignInstance commons:IUser}>
<!--element content here-->
</SomeControl>
是的,这个解决方案看起来并不酷,但绝对不会更糟。
<SomeControl>
<d:SomeControl.DataContext>
<x:Type Type="commons:IUser" />
</d:SomeControl.DataContext>
<!--element content here-->
</SomeControl>
标签允许指定接口,嵌套类型(例如n:A + B)甚至是泛型!
如果是泛型,只需在您的类型中添加一个反引号和多个类型参数:Type
。
BTW所有这些也适用于样式,<x:Type Type="commons:User`1" />
不会产生错误!
答案 1 :(得分:18)
在这种情况下,你可以利用IsDesignTimeCreatable:
d:DataContext="{d:DesignInstance commons:User, IsDesignTimeCreatable=False}"
基本上指示设计者仅使用类型进行智能感知和错误突出显示,而不是实际尝试实例化设计实例。
答案 2 :(得分:5)
我刚刚调查过或多或少相同的问题......实际上,我所做的是遵循MvvMLight的原则。确切地说,我使用了一个ViewModelLocator(它或多或少是静态的),以便在运行时或设计时注入“正确的”ViewModel。神奇之处在于MvvMLight框架提供的函数 ViewModelBase.IsInDesignModeStatic 。最后,我的 ViewModelLocator 类看起来像
public class ViewModelLocator
{
private static readonly IKernel _kernel;
static ViewModelLocator()
{
_kernel = new StandardKernel();
if (ViewModelBase.IsInDesignModeStatic)
{
_kernel.Bind<IBasicVM>().To<DesignBasicVm>();
}
else
{
_kernel.Bind<IBasicVM>().To<BasicVm>();
}
}
public IBasicVM BasicVm { get { return _kernel.Get<IBasicVM>(); } }
}
您可以忽略Ninject _kernel ,但如果您使用IoC构建ViewModel,则可能需要它(或类似的Ioc)。
App.xaml将 ViewModelLocator 声明为资源
<Application.Resources>
<ResourceDictionary>
<viewModel:ViewModelLocator x:Key="ViewModelLocator" />
</ResourceDictionary>
</Application.Resources>
MainWindow.DataContext 属性绑定到 ViewModelLocator 的 BasicVM 成员。 Text属性绑定到接口 IBasicVM 的 GetContent 成员,该成员由R#静态识别(至少R#7.1与VS2012)
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
DataContext="{Binding BasicVm, Source={StaticResource ViewModelLocator}}"
>
<Grid>
<TextBlock Text="{Binding GetContent}"/>
</Grid>
</Window>
您可以查看我创建的this repository作为模板。
答案 3 :(得分:-1)
@Olivier:这是您可以使用“适配器设计模式”的最佳场景之一
注意:我不知道Resharper,我是C#&amp; .NET开发人员。但我理解根据您的解释存在兼容性问题。 以下是您可以尝试的可能解决方案。
示例代码:
class Program
{
static void Main(string[] args)
{
// create an object of your adapter class and consume the features.
AdapterInterfaceUI obj = new AdapterInterfaceUI();
// Even though you have written an adapter it still performs the operation in base class
// which has the interface implementation and returns the value.
// NOTE : you are consuming the interface but the object type is under your control as you are the owner of the adapter class that you have written.
Console.WriteLine(obj.DisplayUI());
Console.ReadKey();
}
}
#region code that might be implemented in the component used.
public interface IinterfaceUI
{
string DisplayUI();
}
public class ActualUI : IinterfaceUI
{
//Factory pattern that would be implemented in the component that you are consuming.
public static IinterfaceUI GetInterfaceObject()
{
return new ActualUI();
}
public string DisplayUI()
{
return "Interface implemented in ActualUI";
}
}
#endregion
#region The adapter class that you may need to implement in resharper or c# which ever works for you.
public class AdapterInterfaceUI : ActualUI, IinterfaceUI
{
public string DisplayUI()
{
return base.DisplayUI();
}
}
#endregion
我认为这个解决方案会帮助你。