我知道这是一个很受欢迎的问题,但我找不到任何确切的答案,但如果我在搜索中遗漏了什么,我会道歉。
我正在尝试创建一个控件,然后在运行时使用以下代码对其进行度量(然后,度量值将用于选取框样式滚动控件-每个控件的大小都不同):
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;
代码创建一个标签控件,并对其应用样式。样式包含绑定到对象“task”的控件模板。当我创建项时,它看起来很完美,但是当我尝试使用上面的任何属性来度量控件时,我得到了以下结果(我依次执行并检查每个属性):
lb.Width = NaN
lb.RenderSize.Width = 0
lb.ActualWidth = 0
是否有任何方法可以获取在运行时创建的控件的呈现高度和宽度?
更新:
很抱歉取消选择您的解决方案作为答案。它们在我设置的一个基本示例系统上工作,但似乎不适用于我的完整解决方案。
我认为这可能与风格有关,所以很抱歉弄乱了,但我把整件事都贴在这里了。
第一,资源:
<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的小把戏?
真正地
恨我?
第二次更新:
在进一步搜索之后,我发现measure()只适用于原始元素的大小。如果控件模板通过实际添加控件来修改这一点,那么最好的方法可能是测量每一个控件,但我承认这不仅仅是一个小问题。
编译器必须有某种方法来测量控件的所有内容,因为它必须使用这些方法来放置项,例如,堆栈面板。一定有什么方法可以接近它,但现在我完全没有主意了。