agrobot_base/AgroBase/OperationControl/Controls/AutoFitTextBlock.cs

139 lines
4.0 KiB
C#
Raw Normal View History

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace OperationControl.Controls
{
public class AutoFitTextBlock : TextBlock
{
public static readonly DependencyProperty MinFontSizeProperty =
DependencyProperty.Register(
nameof(MinFontSize),
typeof(double),
typeof(AutoFitTextBlock),
new PropertyMetadata(10.0, OnAutoFitPropertyChanged));
public static readonly DependencyProperty MaxLinesProperty =
DependencyProperty.Register(
nameof(MaxLines),
typeof(int),
typeof(AutoFitTextBlock),
new PropertyMetadata(2, OnAutoFitPropertyChanged));
private double _baseFontSize = 14;
private bool _isAdjusting;
public double MinFontSize
{
get => (double)GetValue(MinFontSizeProperty);
set => SetValue(MinFontSizeProperty, value);
}
public int MaxLines
{
get => (int)GetValue(MaxLinesProperty);
set => SetValue(MaxLinesProperty, value);
}
public AutoFitTextBlock()
{
Loaded += AutoFitTextBlock_Loaded;
SizeChanged += (_, _) => AdjustFontSize();
}
private void AutoFitTextBlock_Loaded(object sender, RoutedEventArgs e)
{
_baseFontSize = FontSize;
WatchProperty(TextProperty);
WatchProperty(FontSizeProperty);
WatchProperty(FontFamilyProperty);
WatchProperty(FontStyleProperty);
WatchProperty(FontWeightProperty);
WatchProperty(FontStretchProperty);
WatchProperty(TextWrappingProperty);
AdjustFontSize();
}
private void WatchProperty(DependencyProperty dp)
{
var descriptor = DependencyPropertyDescriptor.FromProperty(dp, typeof(AutoFitTextBlock));
descriptor?.AddValueChanged(this, (_, _) =>
{
if (!_isAdjusting && dp == FontSizeProperty)
_baseFontSize = FontSize;
AdjustFontSize();
});
}
private static void OnAutoFitPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is AutoFitTextBlock tb)
tb.AdjustFontSize();
}
private void AdjustFontSize()
{
if (_isAdjusting || !IsLoaded)
return;
if (ActualWidth <= 0 || string.IsNullOrWhiteSpace(Text))
return;
_isAdjusting = true;
try
{
double startFont = _baseFontSize;
double minFont = MinFontSize;
FontSize = startFont;
while (FontSize > minFont)
{
if (Fits(FontSize))
return;
FontSize -= 0.5;
}
FontSize = minFont;
}
finally
{
_isAdjusting = false;
}
}
private bool Fits(double fontSize)
{
double pixelsPerDip = VisualTreeHelper.GetDpi(this).PixelsPerDip;
var formattedText = new FormattedText(
Text ?? string.Empty,
CultureInfo.CurrentUICulture,
FlowDirection,
new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
fontSize,
Foreground,
pixelsPerDip)
{
MaxTextWidth = Math.Max(0, ActualWidth),
Trimming = TextTrimming.None
};
if (TextWrapping == TextWrapping.Wrap)
formattedText.MaxLineCount = MaxLines;
double lineHeight = fontSize * 1.25;
double maxAllowedHeight = lineHeight * MaxLines;
return formattedText.Height <= maxAllowedHeight + 1;
}
}
}