Ich weiß, das ist eine beliebte Frage, aber ich konnte nichts finden, was genau beantwortet, aber ich entschuldige mich, wenn ich etwas bei meinen Recherchen verpasst habe.Messsteuerelemente erstellt zur Laufzeit in WPF
Ich versuche, den folgenden Code ein Steuerelement zur Laufzeit zu erstellen und dann messen mit (die Messungen werden dann um Marquee-Stil die Steuerelemente bewegen verwendet werden - jede Kontrolle eine andere Größe ist):
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;
Der Code erstellt ein Label-Steuerelement und wendet einen Stil darauf an. Der Stil enthält meine Kontrollschablone, die an das Objekt "Aufgabe" bindet. Wenn ich den Artikel erstellen scheint es perfekt, aber wenn ich versuche, die Kontrolle zu messen eine der Eigenschaften unter Verwendung der oben habe ich die folgenden Ergebnisse erhalten (I Schritt durch und jede Eigenschaft wiederum inspizieren):
lb.Width = NaN
lb.RenderSize.Width = 0
lb.ActualWidth = 0
Gibt es eine So erhalten Sie die gerenderte Höhe und Breite eines Steuerelements, das Sie zur Laufzeit erstellen?
UPDATE:
Sorry für Ihre Lösungen als Antworten Abwahl. Sie arbeiten an einem grundlegenden Beispielsystem, das ich eingerichtet habe, aber scheinbar nicht mit meiner vollständigen Lösung.
Ich denke, es könnte etwas mit dem Stil zu tun haben, so leid für die Unordnung, aber ich paste die ganze Sache hier.
Zuerst Ressourcen:
<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>
Und der Stil selbst:
<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>
Auch der Code Ich verwende:
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));
}
Jedes Mal, wenn der Das heißt, der Wert wird entweder als 0 zurückgegeben oder nicht eine Zahl, aber wenn das Etikett gerendert wird, hat es offensichtlich eine Größe, wie es sichtbar ist. Ich habe versucht, diesen Code mit einem Tastendruck auszuführen, wenn das Etikett auf dem Bildschirm sichtbar ist, aber das führt zu denselben Ergebnissen.
Ist es wegen des Stils, den ich verwende? Datenbindungen vielleicht? Ist das, was ich falsch gemacht habe, offensichtlich offensichtlich oder die WPF Gremlins nur wirklich hasse mich?
Zweite Update:
Nach weiterer Suche ich, dass die Maßnahme entdeckt habe() gilt nur für die ursprüngliche Elementgröße. Wenn eine Kontrollschablone dies ändert, indem sie tatsächlich Kontrollen hinzufügt, dann wäre die beste Methode wahrscheinlich, jeden zu messen, aber ich gebe zu, dass das mehr als ein bisschen unordentlich ist.
Der Compiler muss eine Möglichkeit haben, den gesamten Inhalt eines Steuerelements zu messen, da es zum Platzieren von Elementen in z. B. Stack-Panels verwendet werden muss. Es muss einen Weg geben, darauf zuzugreifen, aber im Moment habe ich keine Ideen mehr.
Wohin führen Sie diesen Code? Im Konstruktor des Windows? Wenn dies der Fall ist, müssen Sie warten, bis die Steuerelemente gerendert sind. – Carlo