Pregunta

Al crear un UserControl en WPF, me resulta conveniente darle algunos valores arbitrarios de Alto y Ancho para poder ver mis cambios en el diseñador de Visual Studio.Sin embargo, cuando ejecuto el control, quiero que el Alto y el Ancho no estén definidos, de modo que el control se expanda para llenar cualquier contenedor en el que lo coloque.¿Cómo puedo lograr esta misma funcionalidad sin tener que eliminar los valores de Alto y Ancho antes de crear mi control?(O sin usar DockPanel en el contenedor principal).

El siguiente código demuestra el problema:

<Window x:Class="ExampleApplication3.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:loc="clr-namespace:ExampleApplication3"
    Title="Example" Height="600" Width="600">
    <Grid Background="LightGray">
        <loc:UserControl1 />
    </Grid>
</Window>

La siguiente definición de UserControl1 se muestra razonablemente en tiempo de diseño pero se muestra con un tamaño fijo en tiempo de ejecución:

<UserControl x:Class="ExampleApplication3.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid Background="LightCyan" />
</UserControl>

La siguiente definición de UserControl1 se muestra como un punto en tiempo de diseño pero se expande para llenar el padre Window1 en tiempo de ejecución:

<UserControl x:Class="ExampleApplication3.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid Background="LightCyan" />
</UserControl>
¿Fue útil?

Solución

En Visual Studio agregue el atributo Ancho y Alto a su UserControl XAML, pero en el código subyacente inserte esto

public UserControl1()
{
    InitializeComponent();
    if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
    {
        this.Width = double.NaN; ;
        this.Height = double.NaN; ;
    }
}

Esto verifica si el control se está ejecutando en modo Diseño.Si no (es decir,tiempo de ejecución) establecerá el ancho y el alto en NaN (no es un número), que es el valor que lo establece si elimina los atributos de ancho y alto en XAML.

Entonces, en tiempo de diseño, tendrá el ancho y alto preestablecidos (incluso si coloca el control de usuario en un formulario) y en tiempo de ejecución se acoplará dependiendo de su contenedor principal.

Espero que ayude.

Otros consejos

Para Blend, un truco poco conocido es agregar estos atributos a su control de usuario o ventana:

 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d"
       d:DesignHeight="500" d:DesignWidth="600"

Esto establecerá la altura y el ancho del diseño en 500 y 600 respectivamente.Sin embargo, esto sólo funcionará para el diseñador de mezclas.No el Diseñador de Visual Studio.

En cuanto a Visual Studio Designer, su técnica es lo único que funciona.Por eso no uso Visual Studio Designer.;)

Aquí hay una lista de Atributos de tiempo de diseño en Silverlight Designer.Son los mismos para el diseñador de WPF.

Enumera todos los d: valores disponibles en el Diseñador, como d:DesignHeight, d:DesignWidth, d:IsDesignTimeCreatable, d:CreateList y varios otros.

Hago esto todo el tiempo.Simplemente establezca los valores de ancho y alto en "automático" donde crea una instancia de su control, y esto anulará los valores de tiempo de diseño para ese UserControl.

es decir: <loc:UserControl1 Width="auto" Height="auto" />

Otra opción es establecer una combinación de MinWidth y MinHeight en un tamaño que permita el trabajo en tiempo de diseño, mientras que el Ancho y el Alto permanecen "automáticos".Obviamente, esto solo funciona si no necesita que el UserControl tenga un tamaño menor que los valores mínimos en tiempo de ejecución.

Estaba buscando una solución similar a la que se usa en Blend y con sus menciones creé una clase de comportamiento simple con dos propiedades adjuntas, Ancho y Alto, que se aplican solo en DesinTime.

public static class DesignBehavior 
{
    private static readonly Type OwnerType = typeof (DesignBehavior);

    #region Width

    public static readonly DependencyProperty WidthProperty =
        DependencyProperty.RegisterAttached(
            "Width",
            typeof (double),
            OwnerType,
            new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(WidthChangedCallback)));

    public static double GetWidth(DependencyObject depObj)
    {
        return (double)depObj.GetValue(WidthProperty);
    }

    public static void SetWidth(DependencyObject depObj, double value)
    {
        depObj.SetValue(WidthProperty, value);
    }

    private static void WidthChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        if (DesignerProperties.GetIsInDesignMode(depObj)) {
            depObj.SetValue(FrameworkElement.WidthProperty, e.NewValue);
        }
    }

    #endregion

    #region Height

    public static readonly DependencyProperty HeightProperty =
        DependencyProperty.RegisterAttached(
            "Height",
            typeof (double),
            OwnerType,
            new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(HeightChangedCallback)));

    public static double GetHeight(DependencyObject depObj)
    {
        return (double)depObj.GetValue(HeightProperty);
    }

    public static void SetHeight(DependencyObject depObj, double value)
    {
        depObj.SetValue(HeightProperty, value);
    }


    private static void HeightChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        if (DesignerProperties.GetIsInDesignMode(depObj)) {
            depObj.SetValue(FrameworkElement.HeightProperty, e.NewValue);
        }
    }

    #endregion

}

Luego, en su UserControl, simplemente configura estas propiedades en Xaml

<UserControl x:Class="ExtendedDataGrid.Views.PersonOverviewView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:tool="http://schemas.microsoft.com/wpf/2008/toolkit"
    xmlns:b="clr-namespace:ExtendedDataGrid.Behaviors"
    b:DesignBehavior.Width="600" b:DesignBehavior.Height="200">
    <Grid>
         ...
    </Grid>
</UserControl>

Utilice MinWidth y MinHeight en el control.De esa manera, lo verá en el diseñador y, en tiempo de ejecución, tendrá el tamaño que desee.

Lo hago de manera similar, pero mi solución asegura que si agrega su control a un contenedor en modo de diseño, aparecerá razonablemente.

protected override void OnVisualParentChanged(DependencyObject oldParent)
{
    if (this.Parent != null)
    {
       this.Width = double.NaN;
       this.Height = double.NaN;
    }
}

¿qué opinas?

¡Gracias al respondedor original por esta solución!Para aquellos que estén interesados, aquí está en VB:

If LicenseManager.UsageMode <> LicenseUsageMode.Designtime Then
    Me.Width = Double.NaN
    Me.Height = Double.NaN
End If

Algunos han sugerido usar la propiedad LicenseManager.UsageMode que nunca antes había visto, pero he usado el siguiente código.

if(!DesignerProperties.GetIsInDesignMode(this))
{
    this.Width = double.NaN;
    this.Height = double.NaN;
}

esskar,

Solo quiero agregar que generalmente siempre se debe llamar al método de la base al anular un método "Activado".

protected override void OnVisualParentChanged(DependencyObject oldParent)
{
    base.OnVisualParentChanged(oldParent);

    ...
}

Por cierto, gran solución, ahora también la estoy usando yo mismo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top