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
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
}
}
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)
7条答案
按热度按时间vddsk6oq1#
使用
FormattedText
类。我在代码中创建了一个辅助函数:
它返回可在WPF布局中使用的与设备无关的像素。
vcirk6k62#
为了记录...我假设操作员试图通过编程来确定文本块在添加到可视化树后将占用的宽度。我认为一个比formatedText更好的解决方案(如何处理类似于文本换行的东西?)是在示例文本块上使用Measure和Arrange。
vfwfrxfs3#
所提供的解决方案适用于. Net Framework 4.5,但是,随着Windows 10 DPI扩展和Framework 4.6.x为其添加不同程度的支持,用于度量文本的构造函数现在标记为
[Obsolete]
,以及该方法上不包含pixelsPerDip
参数的任何构造函数。不幸的是,这有点复杂,但新的缩放功能会带来更高的精度。
每次下降的像素数
根据MSDN,这表示:
每个密度无关像素的像素值,相当于缩放因子。例如,如果屏幕的DPI为120(或1.25,因为120/96 = 1.25),则每个密度无关像素绘制1.25个像素。DIP是WPF使用的度量单位,与设备分辨率和DPI无关。
以下是我根据具有DPI缩放感知功能的Microsoft/WPF-Samples GitHub存储库的指导实现的选定答案。
自Windows 10周年纪念日起,* 完全 * 支持DPI扩展还需要一些额外配置(在代码下面),我不能去工作,但如果没有它,它可以在配置了缩放的单个监视器上工作(并考虑缩放变化)。上述存储库中的Word文档是这些信息的来源,因为一旦添加了这些值,应用程序就不会启动。来自同一回购协议的This sample code也用作良好的参考点。
其他要求
根据Microsoft/WPF-Samples上的文档,您需要向应用程序清单中添加一些设置,以涵盖Windows 10周年纪念在多显示器配置中每个显示器具有不同DPI设置的功能。可以合理地猜测,如果没有这些设置,当窗口从一个显示器移动到另一个具有不同设置的显示器时,可能不会引发OnDpiChanged事件。这将使您的测量继续依赖于以前的
DpiScale
。我正在编写的应用程序是为我自己编写的,我没有这样的设置,所以我没有什么可测试的,当我按照指导进行测试时,我最终得到了一个由于明显错误而无法启动的应用程序,所以我放弃了,但最好仔细查看并调整您的应用清单,使其包含:根据文档:
[这]两个标记的组合具有以下效果:1)Windows 10周年更新的每台显示器2)系统〈Windows 10周年更新
js4nwp544#
我通过在后端代码中添加到元素的绑定路径来解决这个问题:
我发现这是一个更干净的解决方案,而不是将上面引用(如FormattedText)的所有开销添加到代码中。
之后,我就能做到这一点:
oxiaedzo5#
我发现了一些很有效的方法...
esbemjvw6#
我用这个:
cpjpxq1n7#
找到这个给你: