根据等宽字体的大小设置WPF RichTextBox的宽度和高度

4

我正在尝试让一个WPF RichTextBox精确地适应特定等宽字体的字符网格。我目前使用FormattedText来确定RichTextBox的宽度和高度,但它提供给我的测量值太小了--具体来说是宽度少了两个字符。

有更好的方法来执行这个任务吗?这似乎不是确定控件大小的合适方式。

RichTextBox rtb;
rtb = new RichTextBox();
FontFamily fontFamily = new FontFamily("Consolas");
double fontSize = 16;
char standardizationCharacter = 'X';
String standardizationLine = "";
for(long loop = 0; loop < columns; loop ++) {
    standardizationLine += standardizationCharacter;
}
standardizationLine += Environment.NewLine;
String standardizationString = "";
for(long loop = 0; loop < rows; loop ++) {
    standardizationString += standardizationLine;
}
Typeface typeface = new Typeface(fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
FormattedText formattedText = new FormattedText(standardizationString, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black);
rtb.Width = formattedText.Width;
rtb.Height = formattedText.Height;

你是如何将文本写入“RichTextBox”中的? - Mike Two
2个回答

6
假设您有一个非常基本的 RichTextBox,只有标准的 FlowDocument,那么您必须考虑到所有额外的布局 RichTextBox 使用。 Document.PagePadding 属性默认为 {5,0,5,0}。因此,您需要将宽度增加 10。
此外,RichTextBox 具有默认值为 {1, 1, 1, 1}BorderThickness。因此,您需要将宽度增加 2。
所以您想要的代码可能如下所示:
var pagePadding = rtb.Document.PagePadding;
var borderThickness = rtb.BorderThickness;
rtb.Width = formattedText.Width
    + pagePadding.Left + pagePadding.Right 
    + borderThickness.Left + borderThickness.Right;

如果您这样做,仍然会少一个字符,但这有点误导。即使文本只比整个字符宽一点,RichTextBox也会换行。如果宽度增加2,就可以解决问题。我无法确定那个额外的2是从哪里来的。我从未尝试过让宽度如此精确。我以前遇到过PagePaddingBorderThickness问题,但我找不到额外的2。它可能只是一个您无法摆脱的常数,但我怀疑。它肯定存在于某个地方。
关于生成StandardizationLine的小技巧,您可以这样做:
string StandardizationLine = new string('X', columns);

清理循环。

很棒的答案。回答你之前的问题,我通过捕获OnPreviewKeyDown和OnPreviewTextInput来向RichTextBox写入,并手动操作Runs内的字符串。 - zope
1
似乎在这个答案中,double.NaN(自动)存在一些问题,但我认为BorderThickness \ PagePadding页面可以解释如何处理这个问题。我还不太确定。 - zope
@oxeb - 你在哪里遇到了 double.NaN 的问题?这并不让我太惊讶。我只是在VS2010中测试了一个只有简单的 RichTextBox 的项目。可能有一些默认值是不同的。我应该声明你可能需要添加错误检查。希望能帮到你。 - Mike Two
太好了!我使用这种技术的组合将其全部工作起来了,对于宽度使用该技术,对于高度则让其自动调整大小,然后通过回调函数将其冻结,基本上是执行 Height = ActualHeight。 - zope

0
我找到了一个 Rich text box 高度问题的解决方案... 我已经修改它以便于一般使用...
在您的应用程序中创建以下结构体....
[StructLayout(LayoutKind.Sequential)]
    public struct RECT {
        public Int32 left;
        public Int32 top;
        public Int32 right;
        public Int32 bottom;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SCROLLBARINFO {
        public Int32 cbSize;
        public RECT rcScrollBar;
        public Int32 dxyLineButton;
        public Int32 xyThumbTop;
        public Int32 xyThumbBottom;
        public Int32 reserved;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public Int32[] rgstate;
    }

在你的类中为表单创建以下私有变量(无论何时需要计算富文本高度):
private UInt32 SB_VERT = 1;
        private UInt32 OBJID_VSCROLL = 0xFFFFFFFB;

        [DllImport("user32.dll")]
        private static extern
            Int32 GetScrollRange(IntPtr hWnd, UInt32 nBar, out Int32 lpMinPos, out Int32 lpMaxPos);

        [DllImport("user32.dll")]
        private static extern
            Int32 GetScrollBarInfo(IntPtr hWnd, UInt32 idObject, ref SCROLLBARINFO psbi);

请在您的类中添加以下方法以用于表单:

private int CalculateRichTextHeight(string richText) {
            int height = 0;
            RichTextBox richTextBox = new RichTextBox();
            richTextBox.Rtf = richText;
            richTextBox.Height = this.Bounds.Height;
            richTextBox.Width = this.Bounds.Width;
            richTextBox.WordWrap = false;
            int nHeight = 0;
            int nMin = 0, nMax = 0;

            SCROLLBARINFO psbi = new SCROLLBARINFO();
            psbi.cbSize = Marshal.SizeOf(psbi);

            richTextBox.Height = 10;
            richTextBox.ScrollBars = RichTextBoxScrollBars.Vertical;

            int nResult = GetScrollBarInfo(richTextBox.Handle, OBJID_VSCROLL, ref psbi);
            if (psbi.rgstate[0] == 0) {
                GetScrollRange(richTextBox.Handle, SB_VERT, out nMin, out nMax);
                height = (nMax - nMin);
            }

            return height;
        }

您可能需要修改上述方法以使其按照您的要求工作... 确保将Rtf字符串作为参数发送到方法中,而不是普通文本,并确保在方法中将可用的宽度和高度分配给Richtextbox变量...

根据您的需求可以调整WordWrap...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接