C# 如何计算已知字体大小和字符的WPF文本块宽度?
假设我有C# 如何计算已知字体大小和字符的WPF文本块宽度?,c#,wpf,font-size,C#,Wpf,Font Size,假设我有TextBlock和text“一些文本”和字体大小10.0 如何计算适当的TextBlock宽度?为您找到了以下内容: Graphics g = control.CreateGraphics(); int width =(int)g.MeasureString(aString, control.Font).Width; g.dispose(); 使用该类 我在代码中创建了一个助手函数: private Size MeasureString(string candidate) {
TextBlock
和text“一些文本”和字体大小10.0
如何计算适当的TextBlock
宽度?为您找到了以下内容:
Graphics g = control.CreateGraphics();
int width =(int)g.MeasureString(aString, control.Font).Width;
g.dispose();
使用该类
我在代码中创建了一个助手函数:
private Size MeasureString(string candidate)
{
var formattedText = new FormattedText(
candidate,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(this.textBlock.FontFamily, this.textBlock.FontStyle, this.textBlock.FontWeight, this.textBlock.FontStretch),
this.textBlock.FontSize,
Brushes.Black,
new NumberSubstitution(),
1);
return new Size(formattedText.Width, formattedText.Height);
}
它返回可在WPF布局中使用的与设备无关的像素。我发现了一些工作正常的方法
/// <summary>
/// Get the required height and width of the specified text. Uses Glyph's
/// </summary>
public static Size MeasureText(string text, FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch, double fontSize)
{
Typeface typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch);
GlyphTypeface glyphTypeface;
if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
{
return MeasureTextSize(text, fontFamily, fontStyle, fontWeight, fontStretch, fontSize);
}
double totalWidth = 0;
double height = 0;
for (int n = 0; n < text.Length; n++)
{
ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[text[n]];
double width = glyphTypeface.AdvanceWidths[glyphIndex] * fontSize;
double glyphHeight = glyphTypeface.AdvanceHeights[glyphIndex] * fontSize;
if (glyphHeight > height)
{
height = glyphHeight;
}
totalWidth += width;
}
return new Size(totalWidth, height);
}
/// <summary>
/// Get the required height and width of the specified text. Uses FortammedText
/// </summary>
public static Size MeasureTextSize(string text, FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch, double fontSize)
{
FormattedText ft = new FormattedText(text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(fontFamily, fontStyle, fontWeight, fontStretch),
fontSize,
Brushes.Black);
return new Size(ft.Width, ft.Height);
}
//
///获取指定文本所需的高度和宽度。使用Glyph的
///
公共静态大小度量文本(字符串文本、FontFamily FontFamily、FontStyle FontStyle、FontWeight FontWeight、FontStretch FontStretch、双fontSize)
{
字体字体=新字体(fontFamily、fontStyle、fontWeight、fontStretch);
字形字体字形字体;
如果(!typeface.TryGetGlyphTypeface(out glyphTypeface))
{
返回MeasureTextSize(文本、fontFamily、fontStyle、fontWeight、fontStretch、fontSize);
}
双总宽度=0;
双倍高度=0;
for(int n=0;n高度)
{
高度=高度;
}
总宽度+=宽度;
}
返回新尺寸(总宽度、高度);
}
///
///获取指定文本所需的高度和宽度。使用FortammedText
///
公共静态大小度量ExtSize(字符串文本、FontFamily FontFamily、FontStyle FontStyle、FontWeight FontWeight、FontStretch FontStretch、double fontSize)
{
FormattedText ft=新的FormattedText(文本,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
新字体(fontFamily、fontStyle、fontWeight、fontStretch),
字体大小,
刷子(黑色);
返回新尺寸(英尺宽、英尺高);
}
我通过向后端代码中的元素添加绑定路径来解决此问题:
<TextBlock x:Name="MyText" Width="{Binding Path=ActualWidth, ElementName=MyText}" />
记录在案。。。
我假设操作员试图通过编程确定文本块在添加到可视化树后所占的宽度。在我看来,一个比formattedText更好的解决方案(如何处理textWrapping之类的事情?)是在示例TextBlock上使用Measure和Arrange。e、 g
var textBlock = new TextBlock { Text = "abc abd adfdfd", TextWrapping = TextWrapping.Wrap };
// auto sized
textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
textBlock.Arrange(new Rect(textBlock.DesiredSize));
Debug.WriteLine(textBlock.ActualWidth); // prints 80.323333333333
Debug.WriteLine(textBlock.ActualHeight);// prints 15.96
// constrain the width to 16
textBlock.Measure(new Size(16, Double.PositiveInfinity));
textBlock.Arrange(new Rect(textBlock.DesiredSize));
Debug.WriteLine(textBlock.ActualWidth); // prints 14.58
Debug.WriteLine(textBlock.ActualHeight);// prints 111.72
提供的解决方案适用于.Net Framework 4.5,但是,随着Windows 10 DPI扩展和Framework 4.6.x增加了不同程度的支持,用于测量文本的构造函数现在标记为
[过时]
,以及该方法上不包含pixelsPerDip
参数的任何构造函数
不幸的是,它有点复杂,但新的缩放功能将带来更高的精度
###像素点
根据MSDN,这表示:
每密度像素独立像素值,相当于比例因子。例如,如果屏幕的DPI为120(或1.25,因为120/96=1.25),则绘制每密度独立像素1.25像素。DIP是WPF使用的测量单位,与设备分辨率和DPI无关
下面是我根据GitHub存储库的指导和DPI扩展意识对所选答案的实现
从Windows 10周年纪念开始,需要一些额外的配置来完全支持DPI扩展(代码下方),我无法使用这些配置,但如果没有它,这可以在配置了扩展的单个监视器上工作(并尊重扩展更改)。上述回购协议中的Word文档就是这些信息的来源,因为一旦我添加了这些值,我的应用程序就不会启动。从同一回购协议也作为一个很好的参考点
public partial class MainWindow : Window
{
private DpiScale m_dpiInfo;
private readonly object m_sync = new object();
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private Size MeasureString(string candidate)
{
DpiScale dpiInfo;
lock (m_dpiInfo)
dpiInfo = m_dpiInfo;
if (dpiInfo == null)
throw new InvalidOperationException("Window must be loaded before calling MeasureString");
var formattedText = new FormattedText(candidate, CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(this.textBlock.FontFamily,
this.textBlock.FontStyle,
this.textBlock.FontWeight,
this.textBlock.FontStretch),
this.textBlock.FontSize,
Brushes.Black,
dpiInfo.PixelsPerDip);
return new Size(formattedText.Width, formattedText.Height);
}
// ... The Rest of Your Class ...
/*
* Event Handlers to get initial DPI information and to set new DPI information
* when the window moves to a new display or DPI settings get changed
*/
private void OnLoaded(object sender, RoutedEventArgs e)
{
lock (m_sync)
m_dpiInfo = VisualTreeHelper.GetDpi(this);
}
protected override void OnDpiChanged(DpiScale oldDpiScaleInfo, DpiScale newDpiScaleInfo)
{
lock (m_sync)
m_dpiInfo = newDpiScaleInfo;
// Probably also a good place to re-draw things that need to scale
}
}
其他要求
根据Microsoft/WPF Samples上的文档,您需要向应用程序清单中添加一些设置,以涵盖Windows 10周年纪念版在多个监视器配置中每个显示器具有不同DPI设置的能力。很有可能,如果没有这些设置,当窗口从一个显示器移动到另一个具有不同设置的显示器时,OnDpiChanged事件可能不会引发,这将使您的测量继续依赖于以前的DpiScale
。我编写的应用程序是为我自己编写的,我没有这样的设置,所以我没有什么可测试的,当我遵循指导时,我最终得到了一个由于明显错误而无法启动的应用程序,因此我放弃了,但最好仔细查看并调整你的应用程序清单,使其包含:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
</windowsSettings>
</application>
真的
永久监测器
根据文件:
[这]两个标记的组合具有以下效果:
1) 每个监视器>=Windows 10周年更新
2) 系统var typeface = new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch);
var formattedText = new FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground);
var size = new Size(formattedText.Width, formattedText.Height)
这是以前问过的,,这也取决于字体。您也可以从
ActualWidth
获取实际宽度。使用TextRenderer也应该适用于WPF:此特定方法仅适用于WinForms。求和字形宽度对大多数字体不起作用,因为它不考虑字体宽度。您只需执行d_width=MyText.ActualWidth代码>无绑定。问题是当TextBlock
还不在可视化树中时。这对如何在UWP@ArunPrasad这将是一个很好的问题,问一个单独的问题。这个问题的范围显然是WPF。如果传入的候选者是一个空格,则返回的宽度为零。我认为这可能与单词包装有关?只需稍作修改,这项工作就完成了
var typeface = new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch);
var formattedText = new FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground);
var size = new Size(formattedText.Width, formattedText.Height)