Gibt es eine Möglichkeit zu überprüfen, ob WPF derzeit im Entwurfsmodus ausgeführt wird oder nicht?

146

Kennt jemand eine globale Statusvariable, die verfügbar ist, damit ich überprüfen kann, ob der Code derzeit im Entwurfsmodus ausgeführt wird (z. B. in Blend oder Visual Studio) oder nicht?

Es würde ungefähr so ​​aussehen:

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

Der Grund, warum ich dies benötige, ist: Wenn meine Anwendung in Expression Blend im Entwurfsmodus angezeigt wird, möchte ich, dass das ViewModel stattdessen eine "Design-Kundenklasse" verwendet, die Scheindaten enthält, die der Designer im Entwurfsmodus anzeigen kann.

Wenn die Anwendung jedoch tatsächlich ausgeführt wird, möchte ich natürlich, dass das ViewModel die echte Kundenklasse verwendet, die echte Daten zurückgibt.

Derzeit löse ich dieses Problem, indem der Designer, bevor er daran arbeitet, das ViewModel aufruft und "ApplicationDevelopmentMode.Executing" in "ApplicationDevelopmentMode.Designing" ändert:

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
quelle

Antworten:

226

Ich glaube, Sie suchen nach GetIsInDesignMode , das ein DependencyObject benötigt.

Dh.

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

Bearbeiten: Wenn Sie Silverlight / WP7 verwenden, sollten Sie verwenden, IsInDesignToolda GetIsInDesignModein Visual Studio manchmal false zurückgegeben werden kann:

DesignerProperties.IsInDesignTool

Bearbeiten: Und der Vollständigkeit halber ist das Äquivalent in WinRT / Metro / Windows Store-Anwendungen DesignModeEnabled:

Windows.ApplicationModel.DesignMode.DesignModeEnabled
Richard Szalay
quelle
3
Als Randnotiz ist IsInDesignMode tatsächlich eine angehängte Eigenschaft, sodass Sie sie auch in einer Bindung von xaml verwenden können. Könnte aber nicht die häufigste Verwendung sein :)
aL3891
3
Vielen Dank, dass Sie die Antwort mit den neuesten XAML- "Anwendungen" wie WinRT und WP auf dem neuesten Stand halten.
Sevenate
In VS2019 Enable project codemuss der Schalter aktiviert sein (oder Menü-> Design-> 🗹 Projektcode ausführen).
marbel82
114

Sie können so etwas tun:

DesignerProperties.GetIsInDesignMode(new DependencyObject());
Sacha Bruttin
quelle
30
Diese Methode funktioniert auch, um ViewModels designfreundlich zu machen (da sie selbst keine DependencyObjects sind).
Pat
1
DependencyObject hat einen geschützten Konstruktor - definieren internal class MyDependencyObject : DependencyObject {}und verwenden new MyDependencyObjectstattDependencyObject
Rico Suter
Wenn Sie dies in einem Ansichtsmodell tun, möchten Sie es wahrscheinlich in eine statische Klasse abstrahieren und das Ergebnis als statischen Booleschen
Wert
24
public static bool InDesignMode()
{
    return !(Application.Current is App);
}

Funktioniert von überall. Ich verwende es, um zu verhindern, dass datengebundene Videos im Designer abgespielt werden.

Patrick
quelle
Eine Variation des oben genannten, Application.Current.MainWindow == nullobwohl mir der Typprüfung besser und direkter gefällt. Es sieht auch so aus, als ob der in Visual Studio gehostete Designer Ressourcen hinzufügt. Hier ist eine andere Möglichkeit, dies zu tun (wenn Sie keinen Zugriff auf den bestimmten AppTyp in der Bibliothek haben, in der sich Ihr Code befindet) ((bool)Application.Current.Resources["ExpressionUseLayoutRounding"]). Sie müssen überprüfen, ob die Ressource zwar nicht vorhanden ist, aber im Designerkontext funktioniert.
John Leidegren
9

Als Visual Studio automatisch Code für mich generierte, wurde dieser verwendet

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

Es gibt andere (möglicherweise neuere) Möglichkeiten, Entwurfszeitdaten in WPF anzugeben, wie in dieser Antwort erwähnt .

Im Wesentlichen können Sie Entwurfszeitdaten mithilfe einer Entwurfszeitinstanz Ihres ViewModel angeben :

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

oder durch Angabe von Beispieldaten in einer XAML-Datei :

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

Sie müssen die SamplePage.xamlDateieigenschaften auf Folgendes einstellen :

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

Ich platziere diese UserControlwie folgt in meinem Tag:

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

Zur Laufzeit verschwinden alle "d:" - Entwurfszeit-Tags, sodass Sie nur Ihren Laufzeitdatenkontext erhalten, unabhängig davon, wie Sie ihn festlegen.

Bearbeiten Möglicherweise benötigen Sie auch diese Zeilen (ich bin nicht sicher, aber sie scheinen relevant zu sein):

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

Und wenn Sie ausgiebig nutzen Caliburn.Micro für Ihre große WPF / Silverlight / WP8 / WinRT Anwendung könnten Sie praktisch und verwenden universelle Caliburn der Execute.InDesignModestatische Eigenschaft in der Ansicht-Modellen als auch (und es funktioniert in Mischung so gut wie in 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
quelle
2

Ich habe dies nur mit Visual Studio 2013 und .NET 4.5 getestet, aber es macht den Trick.

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

Es ist jedoch möglich, dass einige Einstellungen in Visual Studio diesen Wert in false ändern. In diesem Fall können wir nur prüfen, ob dieser Ressourcenname vorhanden ist. Es war, nullals ich meinen Code außerhalb des Designers ausführte.

Der Vorteil dieses Ansatzes besteht darin, dass keine expliziten Kenntnisse der jeweiligen AppKlasse erforderlich sind und dass er global in Ihrem Code verwendet werden kann. Speziell zum Auffüllen von Ansichtsmodellen mit Dummy-Daten.

John Leidegren
quelle
2

Akzeptierte Antwort hat bei mir nicht funktioniert (VS2019).

Nachdem ich mir angesehen hatte, was los war, kam ich auf Folgendes:

    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
quelle
Dies funktionierte für mich, wo ich wissen musste, ob ich in der Entwurfszeit in einem viewModel ausgeführt wurde und keine Windows-Bibliotheken verwenden konnte. Ich weiß, dass es eine sehr kleine Menge an Reflexion ist, aber ich mochte den Gedanken nicht, dass es in der Produktion läuft, also habe ich diesen Code in eine #if DEBUGelse-Rückgabe false eingeschlossen. Gibt es einen Grund, das nicht zu tun?
Toby Smith
1

Ich habe eine Idee für Sie, wenn Ihre Klasse keinen leeren Konstruktor benötigt.

Die Idee ist, einen leeren Konstruktor zu erstellen und ihn dann mit ObsoleteAttribute zu markieren. Der Designer ignoriert das veraltete Attribut, aber der Compiler gibt einen Fehler aus, wenn Sie versuchen, es zu verwenden, sodass kein Risiko besteht, dass Sie es versehentlich selbst verwenden.

( verzeihen Sie meine visuelle Basis )

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

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

Ergebnis des obigen Codes

Dies funktioniert nicht, wenn Sie den leeren Konstruktor wirklich für etwas anderes benötigen.

DonkeyMaster
quelle