Есть ли способ проверить, выполняется ли WPF в настоящее время в режиме разработки или нет?

кто-нибудь знает некоторую глобальную переменную состояния, которая доступна, чтобы я мог проверить, выполняется ли код в настоящее время в режиме разработки (например, в Blend или Visual Studio) или нет?

это будет выглядеть примерно так:

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

причина, по которой мне это нужно: когда мое приложение отображается в режиме дизайна в Expression Blend, я хочу, чтобы ViewModel вместо этого использовал "класс клиента дизайна" , в котором есть макет данных, которые дизайнер может просмотреть в режиме конструктора.

однако, когда приложение фактически выполняется, я, конечно, хочу, чтобы ViewModel использовал реальный класс Customer, который возвращает реальные данные.

В настоящее время я решаю это, имея дизайнера, прежде чем он работает над ним, зайдите в ViewModel и измените "ApplicationDevelopmentMode.Выполнение "to" ApplicationDevelopmentMode.Проектирование":

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);
        }
    }
}

8 ответов


Я считаю, что вы ищете GetIsInDesignMode, который принимает DependencyObject.

Ie.

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

Edit: при использовании Silverlight / WP7 вы должны использовать IsInDesignTool С GetIsInDesignMode иногда может возвращать false в Visual Studio:

DesignerProperties.IsInDesignTool

Edit: и, наконец, в интересах полноты, эквивалент в приложениях WinRT / Metro / Windows Store является DesignModeEnabled:

Windows.ApplicationModel.DesignMode.DesignModeEnabled

вы можете сделать что-то вроде этого:

DesignerProperties.GetIsInDesignMode(new DependencyObject());

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

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


когда Visual Studio автоматически сгенерировал для меня код, он использовал

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

и если вы активно используете Калибурн.Микро!--4--> для WPF / Silverlight / WP8 / WinRT приложение, которое вы можете использовать удобно и универсальная Калибурн это Execute.InDesignMode статическое свойство в ваших view-моделях (и оно работает в 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"
        //};
    }
}

есть другие (возможно, более новые) способы указания данных времени разработки в 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" 

Я тестировал это только с Visual Studio 2013 и .NET 4.5, но это делает трюк.

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

возможно, хотя некоторые настройки в Visual Studio изменят это значение на false, если это когда-либо произойдет, мы можем просто проверить, существует ли это имя ресурса. Это было null когда я запускал свой код вне конструктора.

преимущество этого подхода заключается в том, что он не требует явного знания конкретного App class и что его можно использовать глобально по всему коду. В частности, для заполнения моделей представления фиктивными данными.


у меня есть идея для вас, если ваш класс не нужен пустой конструктор.

идея состоит в том, чтобы создать пустой конструктор, а затем пометить его ObsoleteAttribute. Дизайнер игнорирует устаревший атрибут, но компилятор вызовет ошибку, если вы попытаетесь его использовать, поэтому нет риска случайного использования его самостоятельно.

(простите мой visual basic)

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>

result of the above code

это не будет работать, если вы действительно нужен пустой конструктор для чего-то другого.