Tamanho do tempo de design do WPF UserControl
-
09-06-2019 - |
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>
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.