C'è un modo per verificare se WPF è attualmente in esecuzione in modalità progettazione o no?


147

Qualcuno sa di qualche variabile di stato globale che è disponibile in modo da poter verificare se il codice è attualmente in esecuzione in modalità progettazione (ad esempio in Blend o Visual Studio) o no?

Sarebbe simile a questo:

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

Il motivo per cui ho bisogno di questo è: quando la mia applicazione viene mostrata in modalità progettazione in Expression Blend, voglio che ViewModel utilizzi invece una "Classe cliente di progettazione" che contiene dati simulati che il progettista può visualizzare in modalità progettazione.

Tuttavia, quando l'applicazione viene effettivamente eseguita, ovviamente desidero che ViewModel utilizzi la vera classe Customer che restituisce dati reali.

Attualmente risolvo questo problema facendo in modo che il designer, prima che ci lavori, vada nel ViewModel e cambi "ApplicationDevelopmentMode.Executing" in "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);
        }
    }
}

Risposte:


226

Credo che tu stia cercando GetIsInDesignMode , che richiede un oggetto Dependency.

Vale a dire.

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

Modifica: quando si utilizza Silverlight / WP7, è necessario utilizzare IsInDesignToolpoiché a GetIsInDesignModevolte può restituire false in Visual Studio:

DesignerProperties.IsInDesignTool

Modifica: Infine, nell'interesse della completezza, l'equivalente nelle applicazioni WinRT / Metro / Windows Store è DesignModeEnabled:

Windows.ApplicationModel.DesignMode.DesignModeEnabled

3
Come nota a margine, IsInDesignMode è in realtà una proprietà collegata, quindi puoi usarla anche in un'associazione da xaml. Potrebbe non essere l'uso più comune però :)
aL3891,

3
Grazie per mantenere la risposta aggiornata con le ultime "applicazioni" XAML come WinRT e WP.
Sevenate,

In VS2019 l'interruttore Enable project codedeve essere abilitato (o Menu-> Progettazione-> 🗹 Esegui codice progetto).
marbel82,

115

Puoi fare qualcosa del genere:

DesignerProperties.GetIsInDesignMode(new DependencyObject());

30
Questo metodo funziona anche per rendere ViewModels designer-friendly (poiché non sono oggetti Dependency stessi).
Pat

1
DependencyObject ha un costruttore protetto - definisci internal class MyDependencyObject : DependencyObject {}e usa new MyDependencyObjectinvece diDependencyObject
Rico Suter il


se lo fai in un modello di visualizzazione, probabilmente vorrai
sottrarlo

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

Funziona da qualsiasi luogo. Lo uso per impedire la riproduzione di video di databound nel designer.


Una variazione di quanto sopra, Application.Current.MainWindow == nullanche se mi piace il test di tipo migliore, più diretto. Sembra anche che il designer ospitato in Visual Studio aggiunga risorse, quindi ecco un altro modo per farlo (se non hai accesso al Apptipo specifico nella libreria che ospita il tuo codice) ((bool)Application.Current.Resources["ExpressionUseLayoutRounding"]). È necessario verificare se la risorsa non è presente, ma funziona nel contesto del designer.
John Leidegren,

9

Quando Visual Studio ha generato automaticamente del codice per me, lo ha usato

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

9

Esistono altri (forse più recenti) modi per specificare i dati in fase di progettazione in WPF, come indicato in questa risposta correlata .

In sostanza, è possibile specificare i dati in fase di progettazione utilizzando un'istanza in fase di progettazione di ViewModel :

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

o specificando i dati di esempio in un file XAML :

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

Devi impostare le SamplePage.xamlproprietà del file su:

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

Le inserisco nel mio UserControltag, in questo modo:

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

In fase di runtime, tutti i tag "d:" in fase di progettazione scompaiono, quindi otterrai solo il contesto dei dati di runtime, tuttavia scegli di impostarlo.

Modifica Potresti anche aver bisogno di queste righe (non sono sicuro, ma sembrano rilevanti):

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

7

E se usi ampiamente Caliburn.Micro per la tua grande applicazione WPF / Silverlight / WP8 / WinRT puoi usare anche la proprietà statica di caliburn pratica e universaleExecute.InDesignMode nei tuoi modelli di visualizzazione (e funziona in Blend come 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"
        //};
    }
}

2

Ho provato questo solo con Visual Studio 2013 e .NET 4.5 ma fa il trucco.

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

È possibile, tuttavia, che alcune impostazioni in Visual Studio cambino questo valore in false, se ciò dovesse accadere, potremmo semplicemente verificare l'esistenza di questo nome di risorsa. È stato nullquando ho eseguito il mio codice al di fuori del designer.

Il vantaggio di questo approccio è che non richiede una conoscenza esplicita della Appclasse specifica e che può essere utilizzato a livello globale in tutto il codice. In particolare per popolare i modelli di visualizzazione con dati fittizi.


2

La risposta accettata non ha funzionato per me (VS2019).

Dopo aver ispezionato quello che stava succedendo, mi sono inventato questo:

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

Questo ha funzionato per me dove dovevo sapere se stavo correndo in fase di progettazione da un viewModel e non potevo usare le librerie di Windows. So che è una quantità molto piccola di riflessione, ma non mi piaceva l'idea che funzionasse in produzione, quindi ho racchiuso questo codice in un #if DEBUGaltro return false. C'è qualche motivo per non farlo?
Toby Smith,

1

Ho un'idea per te se la tua classe non ha bisogno di un costruttore vuoto.

L'idea è di creare un costruttore vuoto, quindi contrassegnarlo con ObsoleteAttribute. Il progettista ignora l'attributo obsoleto, ma il compilatore genererà un errore se si tenta di utilizzarlo, quindi non si corre il rischio di utilizzarlo accidentalmente da soli.

( scusate il mio 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

E lo 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>

risultato del codice sopra

Questo non funzionerà se hai davvero bisogno del costruttore vuoto per qualcos'altro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.