Modificando la larghezza e l'altezza WPF RichTextBox secondo la dimensione di un font monospace

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

  •  24-09-2019
  •  | 
  •  

Domanda

Sto cercando di adattare una WPF RichTextBox per accogliere esattamente una griglia di caratteri in un particolare tipo di carattere a spaziatura fissa. Attualmente sto usando FormattedText per determinare la larghezza e l'altezza del mio RichTextBox, ma le misure che sta fornendo me con sono troppo piccole -. In particolare due caratteri di larghezza troppo piccola

C'è un modo migliore per eseguire questa operazione? Questo non sembra essere un modo appropriato per determinare la dimensione del mio controllo.

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;
È stato utile?

Soluzione

Supponendo di avere un RichTextBox molto semplice con solo il FlowDocument di serie al suo interno, allora si deve prendere in considerazione tutti gli usi in più di layout RichTextBox.

Le impostazioni predefinite di proprietà Document.PagePadding a {5,0,5,0}. Così si dovrà aggiungere 10 alla larghezza.

Inoltre, la RichTextBox ha un BorderThickness che il default è {1, 1, 1, 1}. Così si dovrà aggiungere 2 alla larghezza.

Quindi, il codice che si desidera potrebbe apparire come:

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

Se lo fai sarà comunque fuori da 1 carattere, ma questo è un po 'fuorviante. Il RichTextBox avvolgerà anche se il testo è solo un pochino a largo non solo una larghezza di carattere generale. Se si aggiunge 2 alla larghezza va a finire. Io non riesco a capire esattamente dove quel qualcosa in più 2 proviene. Non ho mai cercato di ottenere la larghezza di essere così preciso. Ho eseguito in questioni PagePadding e BorderThickness prima, ma non riesco proprio a trovare il più 2. Potrebbe essere solo una costante si è bloccato con, ma ne dubito. Deve essere da qualche parte.

Una piccola punta sulla produzione del StandardizationLine si può fare

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

per ripulire il ciclo.

Altri suggerimenti

Ho trovato una soluzione per i problemi di altezza casella di testo RTF .. ho modificato un per uso generale ..

Crea seguente struct nell'applicazione ....

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

Create seguenti variabili private nella tua classe per modulo (dove mai è necessario calcolare ricca altezza del testo)

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

Aggiungi seguente metodo alla classe per la forma

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

Potrebbe essere necessario modificare il metodo di cui sopra per farla funzionare secondo il vostro requisito ... Assicurarsi di inviare stringa RTF come parametro per il metodo di testo non è normale e anche fare in modo di larghezza disponibile assegnare e l'altezza alla variabile RichTextBox nel metodo ...

Si può giocare con WordWrap a seconda della vostra esigenza ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top