WPF 如何让 Viewbox 从 StackPanel 中了解其可用空间

Posted

技术标签:

【中文标题】WPF 如何让 Viewbox 从 StackPanel 中了解其可用空间【英文标题】:WPF How to make a Viewbox aware of its available space from within a StackPanel 【发布时间】:2015-06-29 14:45:35 【问题描述】:

我有一个基于 http://www.codeproject.com/Tips/773386/WPF-ImageButton 的 Soroosh Davaee 的 ImageButton 示例的自定义 WPF 控件。自定义控件在 Button 内的水平 StackPanel 中组合了 Image 和 TextBlock。 (顺便说一句,要运行 Soroosh 的示例,我必须编辑解决方案属性,以便“SampleView”是启动项目,而不是“ExtendedButton”作为启动项目。)

如果文本太长而无法自然地放入按钮中,我希望 TextBlock 中的文本在必要时自动缩小,以避免在右边缘剪裁。例如,如果我编辑 Soroosh 的 MainWindow.xaml 以使按钮文本太长而无法容纳...

    ...
    <EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
    ...
    <EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
    ...

...结果是带有剪切文本的以下按钮:

在研究这一点时,自动收缩 TextBlock 内容的最简单方法似乎是将其包装在 Viewbox 中:

<Viewbox StretchDirection="DownOnly" Stretch="Fill">
    <TextBlock ... />
</Viewbox>

DownOnly 显然阻止了 Viewbox 放大 文本以填充空间,而 Fill(与 Uniform 相反)似乎告诉它拉伸(收缩)只有需要缩小的维度(在我的例子中就是水平维度)。​​

在 Soroosh 的示例 Generic.xaml 文件中,我将 TextBlock 包装在这样的 Viewbox 中:

     <Button >
         <StackPanel Orientation="Horizontal">
             <Image Margin="2 0"
                    Source="TemplateBinding Image"
                    Width="TemplateBinding ImageWidth"
                    Height="TemplateBinding ImageHeight"
                    Visibility="TemplateBinding Image,Converter=StaticResource VisibilityConvertor"
                    VerticalAlignment="Center"/>
I added-->   <Viewbox StretchDirection="DownOnly" Stretch="Fill">
             <TextBlock Text="TemplateBinding Content"
                    VerticalAlignment="Center"/>
I added-->   </Viewbox>
         </StackPanel>
     </Button>

这产生了完全相同的剪辑按钮文本。只是在试验,我尝试强制 Viewbox 具有固定宽度...

             <Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">

...产生了这个:

...它显示了 Viewbox 的功能,如果它在 StackPanel 内时能够以某种方式知道其可用宽度。

我确实注意到,如果我将 Viewbox 包裹在整个 StackPanel 周围,它会成功地自动收缩 StackPanel 的全部内容:

     <Button >
         <Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">
             <StackPanel Orientation="Horizontal">
                 <Image Margin="2 0"
                    Source="TemplateBinding Image"
                    Width="TemplateBinding ImageWidth"
                    Height="TemplateBinding ImageHeight"
                    Visibility="TemplateBinding Image,Converter=StaticResource VisibilityConvertor"
                    VerticalAlignment="Center"/>
                 <TextBlock Text="TemplateBinding Content"
                    VerticalAlignment="Center"/>
             </StackPanel>
         </Viewbox>
     </Button>

...产生的结果几乎是我想要的:

...但是图像和文本都缩小了,我希望只缩小文本

我怎样才能使仅包装文本框的视图框从 StackPanel 的单元格中知道其可用宽度(我想是高度)?

【问题讨论】:

【参考方案1】:

这是一个常见问题。解决方案只是使用StackPanel 进行任何需要重新调整子控件大小的布局。这根本不是该工作的正确Panel。相反,请尝试使用Grid 面板,该面板调整其子控件的大小。 StackPanel 控件实际上只适用于最基本的布局任务......尝试任何更冒险的东西,你会发现自己遇到了这些问题。

另一种选择是使用TextBlock.TextTrimming Property 来修剪文本...您也可以将全文放入ToolTip

【讨论】:

同意 100%。人们倾向于过度使用StackPanel,但它有太多的限制,这是主要的:它的潜在可用空间在其物品流动的方向上总是无限的,所以它无法告诉它的孩子他们有多少可用空间朝着那个方向。 感谢您的大开眼界。我没有意识到 StackPanels 有这样的限制。我最终使用了DockPanel,因为它比Grid 更简单。 @phonetagger,您应该知道DockPanel 是一个相当重量级的Panel,并且只有在您需要确切的功能时才应该使用。与DockPanel 相比,Grid Panel 的重量要轻得多,您可以使用它创建相同的显示。 @Sheridan,重量级,你是什么意思?它在哪些方面是重量级的? 重量级如代码、RAM 等,例如。较低的性能。但请忽略该评论......我把它重新放在前面:In what order are Panels the most efficient in terms of render time and performance?。

以上是关于WPF 如何让 Viewbox 从 StackPanel 中了解其可用空间的主要内容,如果未能解决你的问题,请参考以下文章

如何让 WPF TextBlock 在多行上显示我的文本?

WPF的窗口中的所有内容随窗口大小变化而同步变化

StackPanel 内的 WPF ViewBox

WPF 窗口放大缩小控件也跟着放大缩小最好跟网页一样,除了用Viewbox空间

WPF入门教程系列十——布局之Border与ViewBox

WPF入门教程系列九——布局之DockPanel与ViewBox