Apakah ada cara untuk memeriksa apakah WPF saat ini mengeksekusi dalam mode desain atau tidak?

147

Adakah yang tahu tentang beberapa variabel kondisi global yang tersedia sehingga saya dapat memeriksa apakah kode tersebut sedang dijalankan dalam mode desain (misalnya dalam Blend atau Visual Studio) atau tidak?

Akan terlihat seperti ini:

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

Alasan saya membutuhkan ini adalah: ketika aplikasi saya ditampilkan dalam mode desain di Expression Blend, saya ingin ViewModel sebagai gantinya menggunakan "kelas Pelanggan Desain" yang memiliki data tiruan di dalamnya yang dapat dilihat oleh perancang dalam mode desain.

Namun, ketika aplikasi benar-benar dieksekusi, saya tentu saja menginginkan ViewModel untuk menggunakan kelas Pelanggan nyata yang mengembalikan data nyata.

Saat ini saya memecahkan masalah ini dengan meminta desainernya, sebelum ia mengerjakannya, masuk ke ViewModel dan ubah "ApplicationDevelopmentMode.Executing" menjadi "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
sumber

Jawaban:

226

Saya percaya Anda mencari GetIsInDesignMode , yang membutuhkan DependencyObject.

Yaitu.

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

Sunting: Saat menggunakan Silverlight / WP7, Anda harus menggunakan IsInDesignToolkarena GetIsInDesignModekadang-kadang dapat mengembalikan false saat di Visual Studio:

DesignerProperties.IsInDesignTool

Sunting: Dan akhirnya, untuk kepentingan kelengkapan, padanan dalam aplikasi WinRT / Metro / Windows Store adalah DesignModeEnabled:

Windows.ApplicationModel.DesignMode.DesignModeEnabled
Richard Szalay
sumber
3
Sebagai catatan tambahan, IsInDesignMode sebenarnya adalah properti terlampir, sehingga Anda dapat menggunakannya dalam pengikatan dari xaml juga. Mungkin bukan yang paling umum digunakan :)
aL3891
3
Terima kasih telah memperbarui jawabannya dengan "aplikasi" XAML terbaru seperti WinRT dan WP.
Sevenate
Dalam VS2019, sakelar Enable project codeharus diaktifkan (atau Menu-> Desain-> 🗹 Jalankan Kode Proyek).
marbel82
115

Anda dapat melakukan sesuatu seperti ini:

DesignerProperties.GetIsInDesignMode(new DependencyObject());
Sacha Bruttin
sumber
30
Metode ini juga berfungsi untuk membuat ViewModels ramah-desainer (karena mereka bukan DependencyObjects sendiri).
Pat
1
DependencyObject memiliki konstruktor yang dilindungi - tentukan internal class MyDependencyObject : DependencyObject {}dan gunakan new MyDependencyObjectalih-alihDependencyObject
Rico Suter
jika melakukan ini di viewmodel Anda mungkin ingin abstrak itu menjadi kelas statis dan menyimpan hasilnya sebagai boolean statis
Simon_Weaver
24
public static bool InDesignMode()
{
    return !(Application.Current is App);
}

Bekerja dari mana saja. Saya menggunakannya untuk menghentikan video databound dari bermain di perancang.

Patrick
sumber
Variasi di atas Application.Current.MainWindow == nullmeskipun saya suka jenis tes yang lebih baik, lebih langsung. Itu juga tampak seolah-olah desainer yang di-host di Visual Studio menambahkan sumber daya, jadi inilah cara lain untuk melakukannya (jika Anda tidak memiliki akses ke Apptipe spesifik di perpustakaan yang menampung kode Anda) ((bool)Application.Current.Resources["ExpressionUseLayoutRounding"]). Perlu memeriksa jika sumber daya tidak ada di sana tetapi itu berfungsi dalam konteks desainer.
John Leidegren
9

Ketika Visual Studio otomatis menghasilkan beberapa kode untuk saya, itu digunakan

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

Ada cara lain (mungkin yang lebih baru) untuk menentukan data waktu desain di WPF, seperti yang disebutkan dalam jawaban terkait ini .

Pada dasarnya, Anda dapat menentukan data waktu desain menggunakan instance waktu desain ViewModel Anda :

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

atau dengan menentukan data sampel dalam file XAML :

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

Anda harus mengatur SamplePage.xamlproperti file ke:

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

Saya menempatkan ini di UserControltag saya , seperti ini:

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

Saat run-time, semua tag desain-waktu "d:" menghilang, jadi Anda hanya akan mendapatkan konteks data run-time Anda, namun Anda memilih untuk mengaturnya.

Sunting Anda mungkin juga perlu baris-baris ini (saya tidak yakin, tetapi tampaknya relevan):

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

Dan jika Anda secara ekstensif menggunakan Caliburn.Micro untuk aplikasi WPF / Silverlight / WP8 / WinRT besar Anda, Anda dapat menggunakan properti statis caliburn yang praktis dan universalExecute.InDesignMode dalam model tampilan Anda juga (dan berfungsi di Blend dan 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
sumber
2

Saya hanya menguji ini dengan Visual Studio 2013 dan .NET 4.5 tetapi itu berhasil.

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

Meskipun beberapa pengaturan dalam Visual Studio akan mengubah nilai ini menjadi false, jika itu terjadi, kami dapat memeriksa apakah nama sumber daya ini ada. Itu nullketika saya menjalankan kode saya di luar perancang.

Kelebihan dari pendekatan ini adalah bahwa ia tidak memerlukan pengetahuan eksplisit tentang Appkelas tertentu dan dapat digunakan secara global di seluruh kode Anda. Khusus untuk mengisi model tampilan dengan data dummy.

John Leidegren
sumber
2

Jawaban yang diterima tidak berhasil untuk saya (VS2019).

Setelah memeriksa apa yang sedang terjadi, saya datang dengan ini:

    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
sumber
Ini bekerja untuk saya di mana saya perlu tahu apakah saya menjalankan dalam waktu desain dari dalam viewModel dan tidak bisa menggunakan perpustakaan Windows. Saya tahu ini adalah jumlah refleksi yang sangat kecil tetapi saya tidak suka pemikiran itu berjalan dalam produksi jadi saya membungkus kode ini dengan yang #if DEBUGlain mengembalikan false. Apakah ada alasan untuk tidak melakukan itu?
Toby Smith
1

Saya punya ide untuk Anda jika kelas Anda tidak memerlukan konstruktor kosong.

Idenya adalah membuat konstruktor kosong, lalu menandainya dengan ObsoleteAttribute. Perancang mengabaikan atribut usang, tetapi kompiler akan memunculkan kesalahan jika Anda mencoba menggunakannya, jadi tidak ada risiko tidak sengaja menggunakannya sendiri.

( Maafkan visual basic saya )

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

Dan 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>

hasil dari kode di atas

Ini tidak akan berfungsi jika Anda benar - benar membutuhkan konstruktor kosong untuk sesuatu yang lain.

DonkeyMaster
sumber