Existe-t-il un moyen de vérifier si WPF s'exécute actuellement en mode conception ou non?

147

Quelqu'un connaît-il une variable d'état globale disponible pour que je puisse vérifier si le code est actuellement en cours d'exécution en mode conception (par exemple dans Blend ou Visual Studio) ou non?

Cela ressemblerait à quelque chose comme ceci:

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

La raison pour laquelle j'en ai besoin est la suivante: lorsque mon application est affichée en mode conception dans Expression Blend, je souhaite que le ViewModel utilise à la place une "classe Design Customer" qui contient des données simulées que le concepteur peut afficher en mode conception.

Cependant, lorsque l'application s'exécute réellement, je souhaite bien sûr que le ViewModel utilise la classe Customer réelle qui renvoie des données réelles.

Actuellement, je résous ce problème en demandant au concepteur, avant de travailler dessus, d'aller dans le ViewModel et de changer "ApplicationDevelopmentMode.Executing" en "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);
        }
    }
}
Edward Tanguay
la source

Réponses:

226

Je crois que vous recherchez GetIsInDesignMode , qui prend un DependencyObject.

C'est à dire.

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

Edit: Lorsque vous utilisez Silverlight / WP7, vous devez utiliser IsInDesignToolpuisque GetIsInDesignModepeut parfois retourner false dans Visual Studio:

DesignerProperties.IsInDesignTool

Edit: Et enfin, dans un souci d'exhaustivité, l'équivalent dans les applications WinRT / Metro / Windows Store est DesignModeEnabled:

Windows.ApplicationModel.DesignMode.DesignModeEnabled
Richard Szalay
la source
3
En remarque, IsInDesignMode est en fait une propriété attachée, vous pouvez donc également l'utiliser dans une liaison à partir de xaml. Ce n'est peut-être pas l'utilisation la plus courante :)
aL3891
3
Merci de garder la réponse à jour avec les dernières "applications" XAML comme WinRT et WP.
Sevenate
Dans VS2019, le commutateur Enable project codedoit être activé (ou Menu-> Conception-> 🗹 Exécuter le code de projet).
marbel82 le
115

Vous pouvez faire quelque chose comme ceci:

DesignerProperties.GetIsInDesignMode(new DependencyObject());
Sacha Bruttin
la source
30
Cette méthode fonctionne également pour rendre les ViewModels conviviaux pour les concepteurs (car ils ne sont pas des objets DependencyObjects).
Pat
1
DependencyObject a un constructeur protégé - définir internal class MyDependencyObject : DependencyObject {}et utiliser à la new MyDependencyObjectplace deDependencyObject
Rico Suter
3
Le constructeur de @RicoSuter: DependencyObjectest public.
Peter Duniho
si vous faites cela dans un viewmodel, vous voudrez probablement l'abstraire dans une classe statique et stocker le résultat sous forme de booléen statique
Simon_Weaver
24
public static bool InDesignMode()
{
    return !(Application.Current is App);
}

Fonctionne de n'importe où. Je l'utilise pour empêcher la lecture de vidéos basées sur des données dans le concepteur.

Patrick
la source
Une variante de ce qui précède Application.Current.MainWindow == nullbien que j'aime mieux le test de type, plus direct. Il semble également que le concepteur hébergé dans Visual Studio ajoute des ressources, voici donc une autre façon de le faire (si vous n'avez pas accès au Apptype spécifique dans la bibliothèque hébergeant votre code) ((bool)Application.Current.Resources["ExpressionUseLayoutRounding"]). Besoin de vérifier si la ressource n'est pas là, mais cela fonctionne dans le contexte du concepteur.
John Leidegren
9

Lorsque Visual Studio a généré automatiquement du code pour moi, il a utilisé

if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
{
    ...
}
Darren
la source
9

Il existe d'autres moyens (peut-être plus récents) de spécifier des données au moment du design dans WPF, comme mentionné dans cette réponse connexe .

Essentiellement, vous pouvez spécifier des données au moment du design à l'aide d'une instance au moment du design de votre ViewModel :

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

ou en spécifiant des exemples de données dans un fichier XAML :

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

Vous devez définir les SamplePage.xamlpropriétés du fichier sur:

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

Je les place dans mon UserControltag, comme ceci:

<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="...">

Au moment de l'exécution, toutes les balises de conception "d:" disparaissent, vous n'obtiendrez donc que votre contexte de données d'exécution, quelle que soit la manière dont vous le définissez.

Edit Vous pouvez également avoir besoin de ces lignes (je ne suis pas certain, mais elles semblent pertinentes):

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

Et si vous utilisez intensivement Caliburn.Micro pour votre grande application WPF / Silverlight / WP8 / WinRT , vous pouvez également utiliser la propriété statique de caliburn pratique et universelleExecute.InDesignMode dans vos modèles de vue (et cela fonctionne aussi bien dans Blend que dans 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"
        //};
    }
}
Sevenate
la source
2

Je n'ai testé cela qu'avec Visual Studio 2013 et .NET 4.5, mais cela fait l'affaire.

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

Il est possible que certains paramètres de Visual Studio modifient cette valeur en false, si cela se produit, nous pouvons simplement vérifier si ce nom de ressource existe. C'était nullquand j'ai exécuté mon code en dehors du concepteur.

L'avantage de cette approche est qu'elle ne nécessite pas de connaissance explicite de la Appclasse spécifique et qu'elle peut être utilisée globalement dans tout votre code. Spécifiquement pour remplir les modèles de vue avec des données factices.

John Leidegren
la source
2

La réponse acceptée n'a pas fonctionné pour moi (VS2019).

Après avoir inspecté ce qui se passait, j'ai trouvé ceci:

    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");
        }
    }
Ger Hobbelt
la source
Cela a fonctionné pour moi où j'avais besoin de savoir si je fonctionnais au moment du design à partir d'un viewModel et que je ne pouvais pas utiliser les bibliothèques Windows. Je sais que c'est une très petite quantité de réflexion, mais je n'aimais pas l'idée de le faire fonctionner en production, alors j'ai enveloppé ce code dans un #if DEBUGautre return false. Y a-t-il une raison de ne pas faire cela?
Toby Smith
1

J'ai une idée pour vous si votre classe n'a pas besoin d'un constructeur vide.

L'idée est de créer un constructeur vide, puis de le marquer avec ObsoleteAttribute. Le concepteur ignore l'attribut obsolète, mais le compilateur lèvera une erreur si vous essayez de l'utiliser, il n'y a donc aucun risque de l'utiliser accidentellement vous-même.

( pardonnez mon visuel basique )

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

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

résultat du code ci-dessus

Cela ne fonctionnera pas si vous avez vraiment besoin du constructeur vide pour autre chose.

DonkeyMaster
la source