d:具有接口类型的DesignInstance

时间:2013-09-15 16:19:25

标签: c# wpf xaml resharper

我将UI绑定到接口(由几个演示者实现,无法从UI程序集访问)。

我非常喜欢设计师中的D:DesignInstance,因为它(有点)使用R#强力键入xaml。

可悲的是,d:DesignInstance不支持接口类型:“无法创建接口实例。”

Design instance on interface

我想到的第一件事是:好的,没问题,让我们创建一个自定义标记扩展,它将System.Type作为参数,以及哪个ProvideValue方法返回它的假实例(此接口的虚拟实现,由动态生成IL发射。)

这很有效,绑定在设计时被解析(我可以在设计面板中看到,因为我的标记扩展用lorem-ipsum填充了对象属性)

但是最好的R#功能不起作用:Resharper无法识别datacontext类型,只是在“object”类型的数据上下文中给出了“无法解析属性'{0}”的消息/ p>

Custom markup extension

有人知道如何解决这个问题吗?

(允许我让R#了解接口datacontext类型的任何替代方案都会很棒)

谢谢!

ps: 我还尝试创建另一个标记扩展,它返回生成的运行时类型,以便将其提供给DesignInstance:“{d:DesignInstance Type = {utilsUi :InstanceType commons:User}}“=>给出错误“类型'对象InstanceType'无法转换为'System.Type'类型” ......似乎DesignInstance不支持内部标记扩展:(

4 个答案:

答案 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开发人员。但我理解根据您的解释存在兼容性问题。 以下是您可以尝试的可能解决方案。

  1. 编写一个实现所需接口类型的C#类。
  2. 在类中实现接口,但不要自己编写整个实现。而是在实现的方法中调用实现接口的其他类方法。
  3. 开始使用您编写的课程。
  4. 为了获得兼容性而编写的类称为Adapter。
  5. 示例代码:

    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
    

    我认为这个解决方案会帮助你。