Я понимаю, что это популярный вопрос, но я не мог найти ничего, что отвечало бы ему точно, но я прошу прощения, если я пропустил что-то в своих поисках.
Я пытаюсь создать, а затем измерить элемент управления во время выполнения, используя следующий код (измерения затем будут использоваться для выделения в стиле выделения) - каждый элемент управления имеет другой размер):
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;
Код создает элемент управления Label и применяет к нему стиль. Стиль содержит мой шаблон управления, который привязывается к объекту "задача". Когда я создаю элемент, он выглядит отлично, однако, когда я пытаюсь измерить элемент управления с использованием любого из вышеперечисленных свойств, я получаю следующие результаты (я просматриваю и проверяю каждое свойство по очереди):
lb.Width = NaN
lb.RenderSize.Width = 0
lb.ActualWidth = 0
Есть ли способ получить рендерную высоту и ширину элемента управления, созданного во время выполнения?
UPDATE:
Извините за отмену ваших решений в качестве ответов. Они работают над базовой системой, которую я создал, но, похоже, не с моим полным решением.
Я думаю, что это может быть связано со стилем, поэтому извините за беспорядок, но я вставляю все это здесь.
Во-первых, ресурсы:
<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>
И сам стиль:
<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>
Кроме того, код, который я использую:
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));
}
Каждый раз, когда вы вызываете какое-либо из этих значений, значение возвращается как 0 или не число, но когда метка отображается, она явно имеет размер, как видно. Я попытался запустить этот код с нажатия кнопки, когда метка видна на экране, но это дает те же результаты.
Это из-за стиля, который я использую? Возможно, есть привязка к данным? Является ли то, что я сделал неправильно, ослепительно очевидным, или WPF Gremlins просто ненавидят меня?
Второе обновление:
После дальнейшего поиска я обнаружил, что Measure() применим только к размеру исходного элемента. Если шаблон управления изменяет это, добавив элементы управления, лучшим способом, вероятно, будет измерение каждого из них, но я признаю, что это более чем беспорядочно.
У компилятора должен быть какой-то способ измерения всего содержимого элемента управления, поскольку он должен использовать его для размещения элементов, например, в стеке-панелях. Должен быть какой-то способ получить к нему доступ, но на данный момент я полностью исключаю идеи.