Подтвердить что ты не робот

D: DesignInstance с типом интерфейса

Я привязываю интерфейс к интерфейсу (который реализуется несколькими докладчиками, недоступными из сборки пользовательского интерфейса).

Мне очень нравится d: DesignInstance в дизайнере, потому что он (тип) делает xaml строго типизированным с помощью R #.

К сожалению, d: DesignInstance не поддерживает типы интерфейсов: "Невозможно создать экземпляр интерфейса".

Design instance on interface

Первое, что я подумал: "Хорошо, не проблема", создайте собственное расширение разметки, которое принимает параметр System.Type как параметр, и какой метод ProvideValue возвращает поддельный экземпляр (фиктивная реализация этого интерфейса, создаваемая динамическим IL).

Это работает очень хорошо, привязки разрешаются во время разработки (я вижу, что на панели дизайна, так как мое расширение разметки заполняет свойства объекта с помощью lorem-ipsum)

НО самая лучшая функция R # не работает: Resharper не распознает тип datacontext и просто дает сообщение "Невозможно разрешить свойство" {0} 'в контексте данных типа "объект"

Custom markup extension

Кто-нибудь знает, как это исправить?

(любая альтернатива, которая позволила бы мне позволить R # знать об интерфейсе типа datacontext, было бы замечательно)

Спасибо!

ps: Я также попытался создать другое расширение разметки, которое возвращает сгенерированный тип среды выполнения, чтобы передать его DesignInstance: "{d: DesignInstance Type = {utilsUi: Тип экземпляра: пользователь}}" = > Дает ошибку "Объект типа" InstanceType "не может быть преобразован в тип" System.Type" ... кажется, что DesignInstance не поддерживает внутренние расширения разметки: (

4b9b3361

Ответ 1

Я только что исследовал более или менее тот же вопрос... Собственно, я сделал, чтобы следовать принципам MvvMLight. Точно так же я использовал ViewModelLocator (который будет более или менее статичным), чтобы "правый" ViewModel вводился во время выполнения или во время разработки. Магия заключается в функции ViewModelBase.IsInDesignModeStatic, предоставляемой инфраструктурой MvvMLight. Наконец, класс 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), если вы создаете ViewModels с помощью IoC.

App.xaml объявляет ViewModelLocator как ресурс

  <Application.Resources>
    <ResourceDictionary>
      <viewModel:ViewModelLocator x:Key="ViewModelLocator" />
    </ResourceDictionary>
  </Application.Resources>

Свойство MainWindow.DataContext привязано к элементу BasicVM ViewModelLocator. Свойство Text привязано к элементу GetContent интерфейса IBasicVM, который распознается статически 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>

Вы можете проверить этот репозиторий, который я создал как шаблон.

Ответ 2

Вы можете использовать IsDesignTimeCreatable в этом случае так:

d:DataContext="{d:DesignInstance commons:User, IsDesignTimeCreatable=False}"

который по существу инструктирует проектировщика использовать только тип для intellisense и подсвечивание ошибок вместо фактической попытки создания экземпляра проекта.

Ответ 3

Я выяснил, как можно преодолеть эту нелогичную ошибку конструктора Visual Studio XAML.

Вместо

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

Да, это решение выглядит не так круто, но определенно это не намного хуже.

Тег

Type позволяет указать интерфейсы, вложенные типы (например, n: A + B) и даже дженерики!

В случае дженериков просто добавьте обратное отношение и количество аргументов типа к вашему типу: <x:Type Type="commons:User`1" />.

Кстати, все они также работают со стилями, <d:Style.DataContext> не вызывает ошибок!

Ответ 4

@Olivier: Это один из лучших сценариев, где вы можете использовать "Шаблон проектирования адаптера"

Примечание. Я не имею представления о Resharper, я разработчик С# и .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

Я думаю, что это решение поможет вам.