Reconozco que esta es una pregunta popular, pero no pude encontrar nada que respondiera exactamente, pero me disculpo si me perdí algo en mis búsquedas.Controles de medición creados en tiempo de ejecución en WPF
Estoy tratando de crear y luego medir un control en tiempo de ejecución usando el siguiente código (las mediciones a continuación, serán utilizados para marquesina de estilo desplazarse los controles - cada control tiene un tamaño diferente):
Label lb = new Label();
lb.DataContext= task;
Style style = (Style)FindResource("taskStyle");
lb.Style = style;
cnvMain.Children.Insert(0,lb);
width = lb.RenderSize.Width;
width = lb.ActualWidth;
width = lb.Width;
El código crea un control Label y le aplica un estilo. El estilo contiene mi plantilla de control que se une al objeto "tarea". Cuando creo el elemento que aparece a la perfección, sin embargo cuando intento para medir el control de uso de cualquiera de las propiedades antes consigo los resultados siguientes (me paso a través de e inspeccionar cada propiedad a su vez):
lb.Width = NaN
lb.RenderSize.Width = 0
lb.ActualWidth = 0
¿Hay alguna forma de obtener la altura y el ancho representados de un control que creas en el tiempo de ejecución?
ACTUALIZACIÓN:
Lo siento por anular la selección de sus soluciones como respuestas. Trabajan en un sistema de ejemplo básico que configuré, pero aparentemente no con mi solución completa.
Creo que puede tener algo que ver con el estilo, lo siento por el desastre, pero estoy pegando todo aquí.
En primer lugar, los recursos:
<Storyboard x:Key="mouseOverGlowLeave">
<DoubleAnimation From="8" To="0" Duration="0:0:1" BeginTime="0:0:2" Storyboard.TargetProperty="GlowSize" Storyboard.TargetName="Glow"/>
</Storyboard>
<Storyboard x:Key="mouseOverTextLeave">
<ColorAnimation From="{StaticResource buttonLitColour}" To="Gray" Duration="0:0:3" Storyboard.TargetProperty="Color" Storyboard.TargetName="ForeColour"/>
</Storyboard>
<Color x:Key="buttonLitColour" R="30" G="144" B="255" A="255" />
<Storyboard x:Key="mouseOverText">
<ColorAnimation From="Gray" To="{StaticResource buttonLitColour}" Duration="0:0:1" Storyboard.TargetProperty="Color" Storyboard.TargetName="ForeColour"/>
</Storyboard>
Y el estilo propio:
<Style x:Key="taskStyle" TargetType="Label">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Canvas x:Name="cnvCanvas">
<Border Margin="4" BorderBrush="Black" BorderThickness="3" CornerRadius="16">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="1" Color="SteelBlue"/>
<GradientStop Offset="0" Color="dodgerBlue"/>
</LinearGradientBrush>
</Border.Background>
<DockPanel Margin="8">
<DockPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="corbel"/>
<Setter Property="FontSize" Value="40"/>
</Style>
</DockPanel.Resources>
<TextBlock VerticalAlignment="Center" Margin="4" Text="{Binding Path=Priority}"/>
<DockPanel DockPanel.Dock="Bottom">
<Border Margin="4" BorderBrush="SteelBlue" BorderThickness="1" CornerRadius="4">
<TextBlock Margin="4" DockPanel.Dock="Right" Text="{Binding Path=Estimate}"/>
</Border>
<Border Margin="4" BorderBrush="SteelBlue" BorderThickness="1" CornerRadius="4">
<TextBlock Margin="4" DockPanel.Dock="Left" Text="{Binding Path=Due}"/>
</Border>
</DockPanel>
<DockPanel DockPanel.Dock="Top">
<Border Margin="4" BorderBrush="SteelBlue" BorderThickness="1" CornerRadius="4">
<TextBlock Margin="4" Foreground="LightGray" DockPanel.Dock="Left" Text="{Binding Path=List}"/>
</Border>
<Border Margin="4" BorderBrush="SteelBlue" BorderThickness="1" CornerRadius="4">
<TextBlock Margin="4" Foreground="White" DockPanel.Dock="Left" Text="{Binding Path=Name}"/>
</Border>
</DockPanel>
</DockPanel>
</Border>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Además, el código que estoy usando:
Label lb = new Label(); //the element I'm styling and adding
lb.DataContext= task; //set the data context to a custom class
Style style = (Style)FindResource("taskStyle"); //find the above style
lb.Style = style;
cnvMain.Children.Insert(0,lb); //add the style to my canvas at the top, so other overlays work
lb.UpdateLayout(); //attempt a full layout update - didn't work
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
//Synchronize on control rendering
double width = lb.RenderSize.Width;
width = lb.ActualWidth;
width = lb.Width;
})); //this didn't work either
lb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); //nor did this
double testHeight = lb.DesiredSize.Height;
double testWidth = lb.RenderSize.Width; //nor did this
width2 = lb.ActualWidth; //or this
width2 = lb.Width; //or this
//positioning for my marquee code - position off-screen to start with
Canvas.SetTop(lb, 20);
Canvas.SetTop(lb, -999);
//tried it here too, still didn't work
lb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
testHeight = lb.DesiredSize.Height;
//add my newly-created label to a list which I access later to operate the marquee
taskElements.AddLast(lb);
//still didn't work
lb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
testHeight = lb.DesiredSize.Height;
//tried a mass-measure to see if that would work - it didn't
foreach (UIElement element in taskElements)
{
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
}
Cada vez que alguno de Se llama el valor devuelto como 0 o no es un número, sin embargo, cuando se representa la etiqueta, claramente tiene un tamaño tal como es visible. He intentado ejecutar este código desde la pulsación de un botón cuando la etiqueta está visible en la pantalla, pero eso produce los mismos resultados.
¿Es por el estilo que estoy usando? Databindings tal vez? ¿Es obvio que lo que hice mal es obvio o que los Gremlins de WPF solo realmente me odian?
Segundo informe de actualización:
Después se busca más que he descubierto que la Medida() sólo se aplica al tamaño de los elementos originales. Si una plantilla de control modifica esto agregando controles, entonces el mejor método sería medir cada uno, pero admito que es más que un poco desordenado.
El compilador debe tener alguna manera de medir todos los contenidos de un control, ya que debe usar eso para colocar elementos en, por ejemplo, paneles de pila. Debe haber alguna forma de acceder a él, pero por ahora estoy completamente sin ideas.
¿Dónde está ejecutando este código? En el constructor de la ventana? Si es así, debe esperar hasta que se hayan procesado los controles. – Carlo