c# - tutorial - ¿Hay alguna forma de comprobar si WPF se está ejecutando actualmente en modo de diseño o no?
xaml (8)
¿Alguien sabe de alguna variable de estado global que esté disponible para que pueda verificar si el código se está ejecutando actualmente en modo de diseño (por ejemplo, en Blend o Visual Studio) o no?
Se vería algo como esto:
//pseudo code:
if (Application.Current.ExecutingStatus == ExecutingStatus.DesignMode)
{
...
}
La razón por la que necesito esto es cuando mi aplicación se muestre en modo de diseño en Expression Blend, pero quiero que ViewModel use una "Clase de cliente de diseño" que contenga datos simulados que el diseñador puede ver en modo de diseño.
Sin embargo, cuando la aplicación se está ejecutando realmente, por supuesto quiero que ViewModel use la clase real del Cliente que devuelve datos reales.
Actualmente resuelvo esto haciendo que el diseñador, antes de que trabaje en él, vaya al ViewModel y cambie "ApplicationDevelopmentMode.Executing" a "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);
}
}
}
Creo que estás buscando GetIsInDesignMode , que toma un DependencyObject.
Es decir.
// ''this'' is your UI element
DesignerProperties.GetIsInDesignMode(this);
Editar: al usar Silverlight / WP7, debe usar IsInDesignTool
ya que GetIsInDesignMode
veces puede devolver false en Visual Studio:
DesignerProperties.IsInDesignTool
Editar: Y finalmente, en aras de la integridad, el equivalente en las aplicaciones de WinRT / Metro / Windows Store es DesignModeEnabled
:
Windows.ApplicationModel.DesignMode.DesignModeEnabled
Cuando Visual Studio auto generó código para mí, lo usé
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
...
}
Hay otras formas (quizás más nuevas) de especificar datos de tiempo de diseño en WPF, como se menciona en esta respuesta relacionada .
Esencialmente, puede especificar datos de tiempo de diseño usando una instancia en tiempo de diseño de su ViewModel :
d:DataContext="{d:DesignInstance Type=v:MySampleData, IsDesignTimeCreatable=True}"
o al especificar datos de muestra en un archivo XAML :
d:DataContext="{d:DesignData Source=../DesignData/SamplePage.xaml}">
SamplePage.xaml
establecer las propiedades del archivo SamplePage.xaml
en:
BuildAction: DesignData
Copy to Output Directory: Do not copy
Custom Tool: [DELETE ANYTHING HERE SO THE FIELD IS EMPTY]
Los UserControl
en mi etiqueta UserControl
, así:
<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="...">
En tiempo de ejecución, desaparecen todas las etiquetas de tiempo de diseño "d:", por lo que solo obtendrá su contexto de datos en tiempo de ejecución, independientemente de cómo elija configurarlo.
Editar También puede necesitar estas líneas (no estoy seguro, pero parecen relevantes):
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Puedes hacer algo como esto:
DesignerProperties.GetIsInDesignMode(new DependencyObject());
Solo he probado esto con Visual Studio 2013 y .NET 4.5, pero funciona.
public static bool IsDesignerContext()
{
var maybeExpressionUseLayoutRounding =
Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
return maybeExpressionUseLayoutRounding ?? false;
}
Aunque es posible que algunas configuraciones en Visual Studio cambien este valor a falso, si eso ocurre, podemos simplemente verificar si este nombre de recurso existe. Fue null
cuando ejecuté mi código fuera del diseñador.
El lado positivo de este enfoque es que no requiere un conocimiento explícito de la clase de App
específica y que se puede usar globalmente en todo su código. Específicamente para poblar modelos de vista con datos ficticios.
Tengo una idea para ti si tu clase no necesita un constructor vacío.
La idea es crear un constructor vacío, luego marcarlo con ObsoleteAttribute. El diseñador ignora el atributo obsoleto, pero el compilador generará un error si intenta usarlo, por lo que no existe el riesgo de utilizarlo accidentalmente.
( perdón por mi visual básico )
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
Y el 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>
Esto no funcionará si realmente necesita el constructor vacío para otra cosa.
Y si utiliza extensamente Caliburn.Micro para su aplicación WPF / Silverlight / WP8 / WinRT grande, puede usar propiedades estáticas Execute.InDesignMode
prácticas y universales de Execute.InDesignMode
en sus modelos de vista también (y funciona tanto en Blend como en 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"
//};
}
}
public static bool InDesignMode()
{
return !(Application.Current is App);
}
Funciona desde cualquier lugar. Lo uso para detener la reproducción de videos de datos en el diseñador.