Configurando a largura e altura do WPF RichTextBox de acordo com o tamanho de uma fonte monoespaçada

StackOverflow https://stackoverflow.com/questions/2569191

  •  24-09-2019
  •  | 
  •  

Pergunta

Estou tentando ajustar um WPF RichTextBox para acomodar exatamente uma grade de caracteres em uma fonte monoespaçada específica.Atualmente, estou usando o FormattedText para determinar a largura e a altura do meu RichTextBox, mas as medidas que ele me fornece são muito pequenas - especificamente dois caracteres de largura muito pequenos.

Existe uma maneira melhor de realizar esta tarefa?Esta não parece ser uma forma apropriada de determinar o tamanho do meu controle.

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;
Foi útil?

Solução

Supondo que você tenha um muito básico RichTextBox Com apenas o padrão FlowDocument dentro dele, então você tem que levar em consideração todo o layout extra RichTextBox usos.

o Document.PagePadding Propriedade padroniza para {5,0,5,0}. Então você terá que adicionar 10 à largura.

Além disso RichTextBox tem um BorderThickness isso padrão para {1, 1, 1, 1}. Então você terá que adicionar 2 à largura.

Portanto, o código que você deseja pode parecer:

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

Se você fizer isso, ainda estará fora de 1 personagem, mas isso é um pouco enganador. o RichTextBox irá envolver -se mesmo que o texto seja apenas um pouquinho a largura, não apenas uma largura de personagem inteira. Se você adicionar 2 à largura, ele funciona. Não consigo descobrir exatamente de onde vem esse extra 2. Eu nunca tentei ter a largura para ser tão exata. Eu encontrei o PagePadding e BorderThickness Questões antes, mas não consigo encontrar o extra 2. Pode ser apenas uma constante que você está preso, mas duvido. Tem que estar em algum lugar.

Uma pequena dica para produzir o StandardizationLine você pode fazer

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

Para limpar o loop.

Outras dicas

Encontrei uma solução para os problemas de altura da caixa de rich text.eu modifiquei para uso geral ..

Crie as seguintes estruturas em seu aplicativo....

[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;
    }

Crie as seguintes variáveis ​​privadas em sua classe para o formulário (sempre que você precisar calcular a altura do rich text)

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);

Adicione o seguinte método à sua classe para formulário

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;
        }

Pode ser necessário modificar o método acima para fazê-lo funcionar de acordo com suas necessidades ...Certifique-se de enviar a string Rtf como parâmetro para o método, não o texto normal, e também certifique-se de atribuir largura e altura disponíveis à variável Richtextbox no método ...

Você pode brincar com o WordWrap dependendo da sua necessidade...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top