Установка ширины и высоты WPF RichTextBox в соответствии с размером моноширинного шрифта

Я пытаюсь приспособить 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;

2 ответа

Решение

Если у вас есть очень простой RichTextBox только со стандартом FlowDocument внутри него вы должны принять во внимание все дополнительные макеты RichTextBox использует.

Document.PagePadding свойство по умолчанию {5,0,5,0}, Так что вам придется добавить 10 к ширине.

Дополнительно RichTextBox имеет BorderThickness по умолчанию {1, 1, 1, 1}, Так что вам придется добавить 2 к ширине.

Таким образом, код, который вы хотите, может выглядеть так:

var pagePadding = rtb.Document.PagePadding;
var borderThickness = rtb.BorderThickness;
rtb.Width = formattedText.Width
    + pagePadding.Left + pagePadding.Right 
    + borderThickness.Left + borderThickness.Right;

Если вы сделаете это, вы все равно будете отключены на 1 символ, но это немного вводит в заблуждение. RichTextBox будет перенесено, даже если текст будет шириной чуть чуть, а не шириной всего символа. Если вы добавите 2 к ширине, это сработает. Я не могу точно понять, откуда взялись эти дополнительные 2. Я никогда не пытался сделать ширину настолько точной. Я столкнулся с PagePadding а также BorderThickness вопросов раньше, но я просто не могу найти лишние 2. Это может быть просто константа, с которой вы застряли, но я сомневаюсь в этом. Это должно быть где-то.

Небольшой совет по производству StandardizationLine ты можешь сделать

string StandardizationLine = new string('X', columns);

очистить петлю.

Я нашел решение для проблем высоты текстового поля Rich.. Я изменил его для общего использования..

Создайте следующие структуры в вашем приложении....

[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 в качестве параметра для метода, а не обычный текст, а также убедитесь, что в методе присвоены доступная ширина и высота переменной Rich text box в методе.,

Вы можете играть с WordWrap в зависимости от ваших требований...

Другие вопросы по тегам