gpt4 book ai didi

wpf - 如何自动缩放一组控件的字体大小?

转载 作者:行者123 更新时间:2023-12-03 06:14:55 26 4
gpt4 key购买 nike

我在 WPF 网格中有一些 TextBlock,我想根据它们的可用宽度/高度进行缩放。当我搜索自动缩放字体大小时,典型的建议是将 TextBlock 放入 ViewBox 中。

所以我这样做了:

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Viewbox MaxHeight="18" Grid.Column="0" Stretch="Uniform" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="{Binding Text1}" />
</Viewbox>

<Viewbox MaxHeight="18" Grid.Column="1" Stretch="Uniform" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="{Binding Text2}" />
</Viewbox>

<Viewbox MaxHeight="18" Grid.Column="2" Stretch="Uniform" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Text="{Binding Text3}" />
</Viewbox>
</Grid>

它会自动缩放每个 TextBlock 的字体。然而,这看起来很有趣,因为如果其中一个 TextBlock 具有较长的文本,那么它将采用较小的字体,而其相邻的网格元素将采用较大的字体。我希望字体大小按组缩放,如果我可以为一组控件指定“SharedSizeGroup”以自动调整字体大小,也许会很好。

例如

第一个文本 block 文本可能是“3/26/2013 10:45:30 AM”,第二个 TextBlocks 文本可能是“FileName.ext”。如果它们横跨窗口的宽度,则用户开始将窗口的大小调整得越来越小。日期将开始使其字体小于文件名,具体取决于文件名的长度。

理想情况下,一旦其中一个文本字段开始调整字体大小,它们就会全部匹配。有没有人想出一个解决方案,或者可以给我一个机会,告诉我如何让它发挥作用?如果它需要自定义代码,那么希望我们/我可以将其重新打包到自定义混合或附加行为中,以便将来可以重复使用。我认为这是一个非常普遍的问题,但我无法通过搜索找到任何相关内容。

<小时/>

更新我尝试了 Mathieu 的建议,它有点有效,但它有一些副作用:

<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="270" Width="522">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Rectangle Grid.Row="0" Fill="SkyBlue" />

<Viewbox Grid.Row="1" MaxHeight="30" Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="col"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="col"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="col"/>
</Grid.ColumnDefinitions>

<TextBlock Grid.Column="0" Text="SomeLongText" Margin="5" />
<TextBlock Grid.Column="1" Text="TextA" Margin="5" />
<TextBlock Grid.Column="2" Text="TextB" Margin="5" />

</Grid>
</Viewbox>
</Grid>
</Window>

Side-Effects

老实说,缺少比例列对我来说可能没问题。我不介意自动调整列的大小以巧妙地利用空间,但它必须跨越窗口的整个宽度。

注意,如果没有 maxsize,在此扩展示例中,文本太大:

<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="270" Width="522">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Rectangle Grid.Row="0" Fill="SkyBlue" />

<Viewbox Grid.Row="1" Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="col"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="col"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="col"/>
</Grid.ColumnDefinitions>

<TextBlock Grid.Column="0" Text="SomeLongText" Margin="5" />
<TextBlock Grid.Column="1" Text="TextA" Margin="5" />
<TextBlock Grid.Column="2" Text="TextB" Margin="5" />

</Grid>
</Viewbox>
</Grid>

Text too large without MaxSize

在这里,我想限制字体的大小,这样就不会浪费垂直窗口的空间。 我希望输出左、中、右对齐,字体尽可能大,达到所需的最大尺寸。

<小时/>

@adabyron

您提出的解决方案还不错(而且是最好的),但它确实有一些局限性。例如,最初我希望我的列成比例(第二个应该居中)。例如,我的 TextBlock 可能会标记图形的开始、中心和结束,其中对齐很重要。

<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:b="clr-namespace:WpfApplication6.Behavior"
Title="MainWindow" Height="350" Width="525">

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Rectangle Grid.Row="0" Fill="SkyBlue" />
<Line X1="0.5" X2="0.5" Y1="0" Y2="1" Stretch="Fill" StrokeThickness="3" Stroke="Red" />

<Grid Grid.Row="1">

<i:Interaction.Behaviors>
<b:MoveToViewboxBehavior />
</i:Interaction.Behaviors>

<Viewbox Stretch="Uniform" />
<ContentPresenter >
<ContentPresenter.Content>
<Grid x:Name="TextBlockContainer">
<Grid.Resources>
<Style TargetType="TextBlock" >
<Setter Property="FontSize" Value="16" />
<Setter Property="Margin" Value="5" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<TextBlock Grid.Column="0" Text="SomeLongText" VerticalAlignment="Center" HorizontalAlignment="Center" />
<TextBlock Grid.Column="2" Text="TextA" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock Grid.Column="4" Text="TextB" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ContentPresenter.Content>
</ContentPresenter>
</Grid>
</Grid>
</Window>

这是结果。请注意,它不知道它很早就被剪裁了,然后当它替换 ViewBox 时,它看起来好像 Grid 默认为列大小“自动”并且不再居中对齐。

Scaling with adabyron's suggestion

最佳答案

我想编辑我已经提供的答案,但后来决定发布一个新答案更有意义,因为这实际上取决于我更喜欢​​哪个要求。这可能更适合艾伦的想法,因为

  • 中间文本 block 位于窗口中间
  • 可根据高度剪裁调整字体大小
  • 比较通用
  • 不涉及 View 框
<小时/>

enter image description here

enter image description here

other one其优点是

  • 文本 block 的空间分配更有效(没有不必要的边距)
  • 文本 block 可能有不同的字体大小

我还在 StackPanel/DockPanel 类型的顶部容器中测试了此解决方案,表现良好。

请注意,通过调整列/行宽度/高度(自动/星号),您可以获得不同的行为。因此,也可以将所有三个文本 block 列星形化,但这意味着宽度剪切确实会更早发生,并且有更多边距。或者,如果网格所在的行是自动调整大小的,则永远不会发生高度裁剪。

Xaml:

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:beh="clr-namespace:WpfApplication1.Behavior"
Title="MainWindow" Height="350" Width="525">

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.9*"/>
<RowDefinition Height="0.1*" />
</Grid.RowDefinitions>

<Rectangle Fill="DarkOrange" />

<Grid x:Name="TextBlockContainer" Grid.Row="1" >
<i:Interaction.Behaviors>
<beh:ScaleFontBehavior MaxFontSize="32" />
</i:Interaction.Behaviors>
<Grid.Resources>
<Style TargetType="TextBlock" >
<Setter Property="Margin" Value="5" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<TextBlock Grid.Column="0" Text="SomeLongText" />
<TextBlock Grid.Column="1" Text="TextA" HorizontalAlignment="Center" />
<TextBlock Grid.Column="2" Text="TextB" HorizontalAlignment="Right" />
</Grid>
</Grid>
</Window>

缩放字体行为:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using WpfApplication1.Helpers;

namespace WpfApplication1.Behavior
{
public class ScaleFontBehavior : Behavior<Grid>
{
// MaxFontSize
public double MaxFontSize { get { return (double)GetValue(MaxFontSizeProperty); } set { SetValue(MaxFontSizeProperty, value); } }
public static readonly DependencyProperty MaxFontSizeProperty = DependencyProperty.Register("MaxFontSize", typeof(double), typeof(ScaleFontBehavior), new PropertyMetadata(20d));

protected override void OnAttached()
{
this.AssociatedObject.SizeChanged += (s, e) => { CalculateFontSize(); };
}

private void CalculateFontSize()
{
double fontSize = this.MaxFontSize;

List<TextBlock> tbs = VisualHelper.FindVisualChildren<TextBlock>(this.AssociatedObject);

// get grid height (if limited)
double gridHeight = double.MaxValue;
Grid parentGrid = VisualHelper.FindUpVisualTree<Grid>(this.AssociatedObject.Parent);
if (parentGrid != null)
{
RowDefinition row = parentGrid.RowDefinitions[Grid.GetRow(this.AssociatedObject)];
gridHeight = row.Height == GridLength.Auto ? double.MaxValue : this.AssociatedObject.ActualHeight;
}

foreach (var tb in tbs)
{
// get desired size with fontsize = MaxFontSize
Size desiredSize = MeasureText(tb);
double widthMargins = tb.Margin.Left + tb.Margin.Right;
double heightMargins = tb.Margin.Top + tb.Margin.Bottom;

double desiredHeight = desiredSize.Height + heightMargins;
double desiredWidth = desiredSize.Width + widthMargins;

// adjust fontsize if text would be clipped vertically
if (gridHeight < desiredHeight)
{
double factor = (desiredHeight - heightMargins) / (this.AssociatedObject.ActualHeight - heightMargins);
fontSize = Math.Min(fontSize, MaxFontSize / factor);
}

// get column width (if limited)
ColumnDefinition col = this.AssociatedObject.ColumnDefinitions[Grid.GetColumn(tb)];
double colWidth = col.Width == GridLength.Auto ? double.MaxValue : col.ActualWidth;

// adjust fontsize if text would be clipped horizontally
if (colWidth < desiredWidth)
{
double factor = (desiredWidth - widthMargins) / (col.ActualWidth - widthMargins);
fontSize = Math.Min(fontSize, MaxFontSize / factor);
}
}

// apply fontsize (always equal fontsizes)
foreach (var tb in tbs)
{
tb.FontSize = fontSize;
}
}

// Measures text size of textblock
private Size MeasureText(TextBlock tb)
{
var formattedText = new FormattedText(tb.Text, CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(tb.FontFamily, tb.FontStyle, tb.FontWeight, tb.FontStretch),
this.MaxFontSize, Brushes.Black); // always uses MaxFontSize for desiredSize

return new Size(formattedText.Width, formattedText.Height);
}
}
}

视觉助手:

public static List<T> FindVisualChildren<T>(DependencyObject obj) where T : DependencyObject
{
List<T> children = new List<T>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
var o = VisualTreeHelper.GetChild(obj, i);
if (o != null)
{
if (o is T)
children.Add((T)o);

children.AddRange(FindVisualChildren<T>(o)); // recursive
}
}
return children;
}

public static T FindUpVisualTree<T>(DependencyObject initial) where T : DependencyObject
{
DependencyObject current = initial;

while (current != null && current.GetType() != typeof(T))
{
current = VisualTreeHelper.GetParent(current);
}
return current as T;
}

关于wpf - 如何自动缩放一组控件的字体大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15641473/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com