Vra

Vir 'n System.Windows.Forms.TextBox met Multi Line = True, wil ek graag net die rolstawe wys wanneer die teks pas nie.

Dit is 'n leesalleen teksboks slegs gebruik word vir die vertoning. Dit is 'n teksboks sodat gebruikers die teks kan kopieer uit. Is daar enigiets wat 'n ingeboude motor show van rolstawe ondersteun? Indien nie, moet ek wees met 'n ander beheer? Of moet ek haak TextChanged en met die hand te gaan vir oorloop (indien wel, hoe om te sê as die teks pas?)


Nie met 'n bietjie geluk met verskillende kombinasies van WordWrap en rolstawe instellings. Ek wil graag geen rolstawe aanvanklik het en het elke verskyn dinamiese slegs indien die teks pas nie in die gegewe rigting.


@nobugz, dankie, wat werk toe WordWrap is afgeskakel. Ek sal nie verkies om wordwrap skakel, maar dit is die mindere van twee euwels.


@ André Neves, goeie punt, en ek wil hê dat manier gaan as dit gebruiker-bewerkbaar was. Ek stem saam dat konsekwentheid is die kardinale reël vir UI Intuïtie.

Was dit nuttig?

Oplossing

Voeg 'n nuwe klas aan jou projek en plak die kode hieronder getoon. Saam te stel. Drop die nuwe beheer van die top van die toolbox op jou vorm. Dit is nie heeltemal perfek nie, maar behoort te werk vir jou.

using System;
using System.Drawing;
using System.Windows.Forms;

public class MyTextBox : TextBox {
  private bool mScrollbars;
  public MyTextBox() {
    this.Multiline = true;
    this.ReadOnly = true;
  }
  private void checkForScrollbars() {
    bool scroll = false;
    int cnt = this.Lines.Length;
    if (cnt > 1) {
      int pos0 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(0)).Y;
      if (pos0 >= 32768) pos0 -= 65536;
      int pos1 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(1)).Y;
      if (pos1 >= 32768) pos1 -= 65536;
      int h = pos1 - pos0;
      scroll = cnt * h > (this.ClientSize.Height - 6);  // 6 = padding
    }
    if (scroll != mScrollbars) {
      mScrollbars = scroll;
      this.ScrollBars = scroll ? ScrollBars.Vertical : ScrollBars.None;
    }
  }

  protected override void OnTextChanged(EventArgs e) {
    checkForScrollbars();
    base.OnTextChanged(e);
  }

  protected override void OnClientSizeChanged(EventArgs e) {
    checkForScrollbars();
    base.OnClientSizeChanged(e);
  }
}

Ander wenke

Ek het afgekom op hierdie vraag toe ek wou dieselfde probleem op te los.

Die maklikste manier om dit te doen, is om te verander na System.Windows.Forms.RichTextBox. Die eiendom rolstawe in hierdie geval kan gelaat word na die verstek waarde van RichTextBoxScrollBars.Both, wat dui op "beide 'n horisontale en 'n vertikale rolbalk Wys wanneer dit nodig is." Dit sal lekker wees as hierdie funksie is verskaf op teksboks.

Ek ook het 'n paar eksperimente, en het bevind dat die vertikale bar altyd sal wys as jy dit in staat te stel, en die horisontale staaf toon altyd so lank as wat dit in staat gestel en WordWrap == false.

Ek dink jy nie gaan om te kry presies wat jy hier wil. Ek glo egter dat gebruikers wil beter Windows se verstek gedrag as die een wat jy probeer dwing. As ek met jou app, ek sou waarskynlik gepla as my teksboks real-boedel skielik gekrimp net omdat dit nodig het om 'n onverwagse scrollbar akkommodeer, want ek het dit te veel teks!

Miskien is dit 'n goeie idee wees net om jou te laat jou aansoek Windows 'n blik volg en voel.

Daar is 'n uiters subtiele fout in oplossing nobugz se wat lei tot 'n hoop korrupsie, maar net as jy met behulp van AppendText () om die teksboks te werk.

Die opstel van die rolstawe eiendom van OnTextChanged sal veroorsaak dat die Win32 venster (handvatsel) te vernietig en herskep. Maar OnTextChanged genoem uit die ingewande van die Win32 wysig beheer (EditML_InsertText), wat onmiddellik daarna verwag dat die interne toestand van daardie Win32 wysig beheer onveranderd wees. Ongelukkig, omdat die venster is herskep, wat interne staat is bevry deur die bedryfstelsel, wat lei tot 'n toegang fout.

So het die moraal van die storie is:. Moenie AppendText () nie gebruik as jy gaan om oplossing nobugz se gebruik

Ek het 'n paar sukses met die onderstaande kode.

  public partial class MyTextBox : TextBox
  {
    private bool mShowScrollBar = false;

    public MyTextBox()
    {
      InitializeComponent();

      checkForScrollbars();
    }

    private void checkForScrollbars()
    {
      bool showScrollBar = false;
      int padding = (this.BorderStyle == BorderStyle.Fixed3D) ? 14 : 10;

      using (Graphics g = this.CreateGraphics())
      {
        // Calcualte the size of the text area.
        SizeF textArea = g.MeasureString(this.Text,
                                         this.Font,
                                         this.Bounds.Width - padding);

        if (this.Text.EndsWith(Environment.NewLine))
        {
          // Include the height of a trailing new line in the height calculation        
          textArea.Height += g.MeasureString("A", this.Font).Height;
        }

        // Show the vertical ScrollBar if the text area
        // is taller than the control.
        showScrollBar = (Math.Ceiling(textArea.Height) >= (this.Bounds.Height - padding));

        if (showScrollBar != mShowScrollBar)
        {
          mShowScrollBar = showScrollBar;
          this.ScrollBars = showScrollBar ? ScrollBars.Vertical : ScrollBars.None;
        }
      }
    }

    protected override void OnTextChanged(EventArgs e)
    {
      checkForScrollbars();
      base.OnTextChanged(e);
    }

    protected override void OnResize(EventArgs e)
    {
      checkForScrollbars();
      base.OnResize(e);
    }
  }

Wat Aidan beskryf is byna presies die UI scenario ek in die gesig staar. As die teks boks net gelees word, weet ek nie nodig het om te reageer op TextChanged. En Ek sal verkies om die motor-scroll herberekening te vertraag sodat dit nie dosyne kere per sekonde is vuur terwyl 'n venster word aangepas.

Vir die meeste Uis, teks bokse met beide vertikale en horisontale scroll bars is, wel, kwaad, so ek is in vertikale scroll bars hier net belangstel.

Ek het ook bevind dat MeasureString het 'n hoogte wat eintlik groter as wat nodig was, was. Die gebruik van die teks boks se PreferredHeight met geen grens as die lyn hoogte gee 'n beter resultaat.

Die volgende blyk baie goed werk, met of sonder 'n grens, en dit werk met WordWrap op.

eenvoudig noem AutoScrollVertically () wanneer jy dit nodig het, en opsioneel spesifiseer recalculateOnResize.

public class TextBoxAutoScroll : TextBox
{
    public void AutoScrollVertically(bool recalculateOnResize = false)
    {
        SuspendLayout();

        if (recalculateOnResize)
        {
            Resize -= OnResize;
            Resize += OnResize;
        }

        float linesHeight = 0;
        var   borderStyle = BorderStyle;

        BorderStyle       = BorderStyle.None;

        int textHeight    = PreferredHeight;

        try
        {
            using (var graphics = CreateGraphics())
            {
                foreach (var text in Lines)
                {
                    var textArea = graphics.MeasureString(text, Font);

                    if (textArea.Width < Width)
                        linesHeight += textHeight;
                    else
                    {
                        var numLines = (float)Math.Ceiling(textArea.Width / Width);

                        linesHeight += textHeight * numLines;
                    }
                }
            }

            if (linesHeight > Height)
                ScrollBars = ScrollBars.Vertical;
            else
                ScrollBars = ScrollBars.None;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex);
        }
        finally
        {
            BorderStyle = borderStyle;

            ResumeLayout();
        }
    }

    private void OnResize(object sender, EventArgs e)
    {
        m_timerResize.Stop();

        m_timerResize.Tick    -= OnDelayedResize;
        m_timerResize.Tick    += OnDelayedResize;
        m_timerResize.Interval = 475;

        m_timerResize.Start();
    }

    Timer m_timerResize = new Timer();

    private void OnDelayedResize(object sender, EventArgs e)
    {
        m_timerResize.Stop();

        Resize -= OnResize;

        AutoScrollVertically();

        Resize += OnResize;
    }
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top