Чи є спосіб перевірити, чи в даний час WPF виконується в режимі проектування чи ні?


147

Хтось знає про якусь змінну глобального стану, яка доступна, щоб я міг перевірити, чи виконується цей код у режимі проектування (наприклад, у Blend чи Visual Studio) чи ні?

Це виглядатиме приблизно так:

//pseudo code:
if (Application.Current.ExecutingStatus == ExecutingStatus.DesignMode) 
{
    ...
}

Причина, яка мені потрібна, полягає в тому, що коли моя програма відображається в режимі дизайну в Expression Blend, я хочу, щоб ViewModel замість цього використовував "Клас дизайну клієнтів", в якому є макетні дані, які дизайнер може переглядати в режимі дизайну.

Однак, коли програма фактично виконується, я, звичайно, хочу, щоб ViewModel використовував реальний клас клієнтів, який повертає реальні дані.

В даний час я вирішую це, коли дизайнер перед тим, як він буде працювати над ним, переходить у ViewModel і змінює "ApplicationDevelopmentMode.Executing" на "ApplicationDevelopmentMode.Designing":

public CustomersViewModel()
{
    _currentApplicationDevelopmentMode = ApplicationDevelopmentMode.Designing;
}

public ObservableCollection<Customer> GetAll
{
    get
    {
        try
        {
            if (_currentApplicationDevelopmentMode == ApplicationDevelopmentMode.Developing)
            {
                return Customer.GetAll;
            }
            else
            {
                return CustomerDesign.GetAll;
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
}

Відповіді:


226

Я вважаю, що ви шукаєте GetIsInDesignMode , який приймає DependencyObject.

Тобто

// 'this' is your UI element
DesignerProperties.GetIsInDesignMode(this);

Редагувати: Коли ви використовуєте Silverlight / WP7, вам слід користуватися, IsInDesignToolоскільки GetIsInDesignModeіноді можна повернути помилкові, перебуваючи в Visual Studio:

DesignerProperties.IsInDesignTool

Редагувати: Нарешті, в інтересах повноти еквівалент програм WinRT / Metro / Windows Store становить DesignModeEnabled:

Windows.ApplicationModel.DesignMode.DesignModeEnabled

3
Як бічна примітка, IsInDesignMode насправді є доданою властивістю, тому ви можете використовувати її також у прив'язці від xaml. Можливо, це не найпоширеніший спосіб використання :)
aL3891

3
Дякуємо за те, що ви відповідали за новітні програми XAML, такі як WinRT та WP.
Севанат

У VS2019 перемикач Enable project codeповинен бути включений (або Меню-> Дизайн-> 🗹 Запустити проектний код).
marbel82

115

Ви можете зробити щось подібне:

DesignerProperties.GetIsInDesignMode(new DependencyObject());

30
Цей метод також працює для створення дизайнера ViewModels, сприятливого для дизайнерів (оскільки вони самі не є DependencyObjects).
Пат

1
DependencyObject має захищений конструктор - визначте internal class MyDependencyObject : DependencyObject {}та використовуйте new MyDependencyObjectзамістьDependencyObject
Rico Suter


якщо ви робите це у моделі перегляду, ви, ймовірно, хочете абстрагувати його у статичний клас і зберегти результат як статичний булевий
Simon_Weaver

24
public static bool InDesignMode()
{
    return !(Application.Current is App);
}

Працює з будь-якого місця. Я використовую його для того, щоб зупинити відтворення відеозаписів, відтворених у дизайнері.


Варіація вищезазначеного, Application.Current.MainWindow == nullхоча мені подобається тест на тип краще, пряміший. Також здається, що дизайнер, розміщений у Visual Studio, додає ресурси, тож ось ще один спосіб зробити це (якщо у вас немає доступу до певного Appтипу в бібліотеці, що розміщує ваш код) ((bool)Application.Current.Resources["ExpressionUseLayoutRounding"]). Потрібні перевірки, якщо ресурсу немає, хоча він працює в дизайнерському контексті.
Джон Лейдегрен

9

Коли Visual Studio автоматично генерував якийсь код для мене, він використовувався

if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
{
    ...
}

9

Існують інші (можливо новіші) способи визначення даних про час проектування у WPF, про що йдеться у цій відповіді .

По суті, ви можете вказати дані про час проектування, використовуючи примірник часу проектування вашого ViewModel :

d:DataContext="{d:DesignInstance Type=v:MySampleData, IsDesignTimeCreatable=True}"

або вказавши зразкові дані у файлі XAML :

d:DataContext="{d:DesignData Source=../DesignData/SamplePage.xaml}">

Ви повинні встановити SamplePage.xamlвластивості файлу:

BuildAction:               DesignData
Copy to Output Directory:  Do not copy
Custom Tool:               [DELETE ANYTHING HERE SO THE FIELD IS EMPTY]

Я розміщую їх у своєму UserControlтезі, наприклад:

<UserControl
    ...
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    ...
    d:DesignWidth="640" d:DesignHeight="480"
    d:DataContext="...">

Під час виконання всі теги "d:" для дизайну зникають, тому ви отримаєте лише контекст даних про час виконання, однак ви вирішите його встановити.

Редагування Вам також можуть знадобитися ці рядки (я не впевнений, але вони здаються актуальними):

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d" 

7

І якщо ви широко використовуєте Caliburn.Micro для свого великого додатка WPF / Silverlight / WP8 / WinRT, ви можете використовувати зручну і універсальнуExecute.InDesignMode статичну властивість калібру у ваших моделях перегляду (і він працює в Blend так само добре, як і у Visual Studio):

using Caliburn.Micro;

// ...

/// <summary>
/// Default view-model's ctor without parameters.
/// </summary>
public SomeViewModel()
{
    if(Execute.InDesignMode)
    {
        //Add fake data for design-time only here:

        //SomeStringItems = new List<string>
        //{
        //  "Item 1",
        //  "Item 2",
        //  "Item 3"
        //};
    }
}

2

Я тестував це лише за допомогою Visual Studio 2013 та .NET 4.5, але це робить свою справу.

public static bool IsDesignerContext()
{
  var maybeExpressionUseLayoutRounding =
    Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
  return maybeExpressionUseLayoutRounding ?? false;
}

Цілком можливо, що деякі параметри у Visual Studio змінять це значення на помилкове, якщо це коли-небудь трапиться, ми можемо призвести до просто перевірки, чи існує це ім'я ресурсу. Це було nullколи я запустив свій код поза дизайнера.

Перевага цього підходу полягає в тому, що він не вимагає явного знання конкретного Appкласу і що його можна використовувати в усьому світі у вашому коді. Зокрема, для заповнення моделей перегляду за допомогою фіктивних даних.


2

Прийнята відповідь не працювала для мене (VS2019).

Оглянувши, що відбувається, я придумав таке:

    public static bool IsRunningInVisualStudioDesigner
    {
        get
        {
            // Are we looking at this dialog in the Visual Studio Designer or Blend?
            string appname = System.Reflection.Assembly.GetEntryAssembly().FullName;
            return appname.Contains("XDesProc");
        }
    }

Це працювало для мене там, де мені потрібно було знати, чи я працюю в проектний час зсередини viewModel і не можу використовувати бібліотеки Windows. Я знаю, що це дуже невелика кількість роздумів, але мені не сподобалася думка про те, що він працює у виробництві, тому я загорнув цей код у #if DEBUGінший варіант false. Чи є якісь причини цього не робити?
Тобі Сміт

1

У мене є ідея для вас, якщо вашому класу не потрібен порожній конструктор.

Ідея полягає у створенні порожнього конструктора, а потім позначте його ObsoleteAttribute. Дизайнер ігнорує застарілий атрибут, але компілятор викличе помилку, якщо ви спробуєте ним скористатися, тому немає ризику випадкового використання його самостійно.

( пробачте мою візуальну основу )

Public Class SomeClass

    <Obsolete("Constructor intended for design mode only", True)>
    Public Sub New()
        DesignMode = True
        If DesignMode Then
            Name = "Paula is Brillant"
        End If
    End Sub

    Public Property DesignMode As Boolean
    Public Property Name As String = "FileNotFound"
End Class

І xaml:

<UserControl x:Class="TestDesignMode"
             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:vm="clr-namespace:AssemblyWithViewModels;assembly=AssemblyWithViewModels"
             mc:Ignorable="d" 
             >
  <UserControl.Resources>
    <vm:SomeClass x:Key="myDataContext" />
  </UserControl.Resources>
  <StackPanel>
    <TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding DesignMode}" Margin="20"/>
    <TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding Name}" Margin="20"/>
  </StackPanel>
</UserControl>

результат вищевказаного коду

Це не спрацює, якщо вам справді потрібен порожній конструктор для чогось іншого.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.