6

Когда для дизайнера указываю в DataContext VM-ку у которой нет конструктора по умолчанию то он всегда на это ругается. Как можно исправить эту ситуацию?

d:DataContext="{d:DesignInstance local:AuthenticationVm,
                                          IsDesignTimeCreatable=True}"

введите сюда описание изображения

VladD
  • 206,799
Lightness
  • 3,476

1 Answers1

11

Если у вас указано IsDesignTimeCreatable=True, дизайнер WPF попытается создать объект этого класса, и использовать в качестве DataContext для отображения. Для этого ему нужен конструктор без параметров.

Если у вас указано IsDesignTimeCreatable=False, дизайнер WPF не будет пытаться создать объект. Вместо этого он создаст свой фейковый тип данных с такими же открытыми свойствами, инстанциирует его, и будет использовать в качестве DataContext'а.


Когда вы указываете IsDesignTimeCreatable=False, вы больше не будеет видеть в дизайнере данные. Это может быть не очень удобно. Вот более продвинутый способ, который позволяет видеть данные в дизайнере даже если у вашей VM нет конструктора без аргументов.

Для этого нужно создать данные для дизайнера. Допустим, у нас есть такой VM-класс:

class VM
{
    public VM(string text) { Text = text; } 
    public string Text { get; }
}

Как мы видим, у этого класса нет конструктора без параметров, и у его свойства нету сеттера. Это нам не помеха.

Заводим в проекте ResourceDictionary (пусть он называется DesignDictionary.xaml, точное название не важно). Когда вы его создадите, он будет выглядеть как-то так:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:MyCoolProject">

</ResourceDictionary>

Удалите всё это (!) и положите вместо него объявление экземпляра вашего VM-класса:

<local:VM xmlns:local="clr-namespace:MyCoolProject" Text="Design Text"/>

Теперь зайдите в свойства файла, и задайте ему Build Action = DesignData и удалите Custom Tool:

design data

Теперь этот экземпляр можно использовать следующим образом:

<Grid d:DataContext="{d:DesignData Source=DesignDictionary.xaml}">
    <TextBlock Text="{Binding Text}"/>
</Grid>

Не забудьте перекомпилировать проект. Теперь в дизайнере отображаются данные:

результат налицо

Всё, мы обошли ограничения дизайнера WPF.

Литература: MSDN/WPF Designer blog/Sample Data in the WPF and Silverlight Designer.


Ещё одной идеей для борьбы с проблемой может быть создание специального производного класса (только для использования в дизайнере), в котором будет конструктор по умолчанию. Этот конструктор будет вызывать базовый конструктор с какими-нибудь подходящими параметрами. Чтобы случайно не использовать этот класс в реальном коде, можно дать ему атрибут [Obsolete].

VladD
  • 206,799
  • Понял, спасибо! – Lightness Sep 24 '16 at 18:17
  • @Lightness: Посмотрите в обновление ответа, добавил ещё один интересный вариант. – VladD Sep 24 '16 at 19:26
  • Интересные подходы! Спасибо! – Lightness Sep 25 '16 at 07:46
  • @VladD, а можно ли сделать конструктор без параметров только для DesignInstance, чтобы случайно не воспользоваться им в коде? – Gardes Oct 06 '16 at 10:45
  • 1
    @S.Kost: Можно. Поставьте ему атрибут [Obsolete]. – VladD Oct 06 '16 at 11:23
  • @VladD, помечает как "устаревший", но все равно компилируется если вызвать его. Спасибо за совет. Оказывается это было в ответе, я не заметил) – Gardes Oct 06 '16 at 11:39