Pergunta

Ao criar um UserControl no WPF, acho conveniente fornecer alguns valores arbitrários de altura e largura para que eu possa visualizar minhas alterações no designer do Visual Studio.No entanto, quando executo o controle, quero que a Altura e a Largura sejam indefinidas, para que o controle se expanda para preencher qualquer contêiner em que eu o colocar.Como posso obter essa mesma funcionalidade sem precisar remover os valores de Altura e Largura antes de criar meu controle?(Ou sem usar DockPanel no contêiner pai.)

O código a seguir demonstra o 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>

A seguinte definição de UserControl1 é exibido razoavelmente em tempo de design, mas é exibido como um tamanho fixo em tempo de execução:

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

A seguinte definição de UserControl1 é exibido como um ponto em tempo de design, mas se expande para preencher o pai Window1 em tempo de execução:

<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>
Foi útil?

Solução

No Visual Studio, adicione o atributo Width e Height ao seu UserControl XAML, mas no code-behind insira isso

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

Isso verifica se o controle está sendo executado no modo Design.Se não (ou seja,runtime), ele definirá Width e Height como NaN (não um número), que é o valor definido se você remover os atributos Width e Height em XAML.

Portanto, em tempo de design, você terá a largura e a altura predefinidas (inclusive se você colocar o controle de usuário em um formulário) e em tempo de execução ele será encaixado dependendo do contêiner pai.

Espero que ajude.

Outras dicas

Para o Blend, um truque pouco conhecido é adicionar estes atributos ao seu usercontrol ou janela:

 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"

Isso definirá a altura e a largura do design para 500 e 600, respectivamente.No entanto, isso só funcionará para o designer de mistura.Não é o Visual Studio Designer.

No que diz respeito ao Visual Studio Designer, sua técnica é tudo o que funciona.É por isso que não uso o Visual Studio Designer.;)

Aqui está uma lista de Atributos de tempo de design no Silverlight Designer.Eles são iguais para o designer WPF.

Ele lista todos os d: valores disponíveis no Designer, como d:DesignHeight, d:DesignWidth, d:IsDesignTimeCreatable, d:CreateList e vários outros.

Eu faço isso toda hora.Basta definir os valores de largura e altura como "auto" onde você instancia seu controle, e isso substituirá os valores de tempo de design desse UserControl.

ou seja: <loc:UserControl1 Width="auto" Height="auto" />

Outra opção é definir uma combinação de MinWidth e MinHeight para um tamanho que permita o trabalho em tempo de design, enquanto Width e Height permanecem "automáticos".Obviamente, isso só funciona se você não precisar que o UserControl seja menor que os valores mínimos em tempo de execução.

Eu estava procurando uma solução semelhante à usada no Blend e com suas menções criei uma classe de comportamento simples com duas propriedades anexadas Largura e Altura que são aplicadas apenas no 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

}

Então no seu UserControl você acabou de definir essas propriedades em 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>

Use MinWidth e MinHeight no controle.Dessa forma, você verá no designer, e em tempo de execução ele será dimensionado da maneira que você desejar.

Eu faço de forma semelhante, mas minha solução garante que se você adicionar seu controle a um contêiner no modo de design, ele aparecerá razoavelmente.

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

o que você acha?

Obrigado ao respondente original por esta solução!Para quem estiver interessado, aqui está em VB:

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

Alguns sugeriram o uso da propriedade LicenseManager.UsageMode que nunca vi antes, mas usei o código a seguir.

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

Essekar,

Só quero acrescentar que geralmente você sempre deve chamar o método base ao substituir um método "On".

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

    ...
}

A propósito, ótima solução alternativa, também estou usando agora.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top