Автоматична вертикальна смуга прокрутки в текстовому блоці WPF?


336

У мене є TextBlockWPF. Я пишу до нього багато рядків, значно перевищуючи його вертикальну висоту. Я очікував, що вертикальна смуга прокрутки автоматично з’явиться, коли це станеться, але цього не сталося. Я намагався шукати властивість смуги прокрутки на панелі властивостей, але не зміг її знайти.

Як я можу зробити так, щоб вертикальна смуга прокрутки була створена автоматично, TextBlockколи вміст перевищує її висоту?

Уточнення: я б краще це робив від дизайнера, а не безпосередньо писав до XAML.


1
Перечитавши це запитання, я помічаю, що ви згадуєте TextBlockдвічі та TextBoxраз.
Дрю Ноакс

Відповіді:


555

Загорніть його в переглядач прокрутки:

<ScrollViewer>
    <TextBlock />
</ScrollViewer>

ПРИМІТКА. Ця відповідь стосується TextBlock(текстового елемента, доступного лише для читання), про що вимагається в оригінальному запитанні.

Якщо ви хочете показати смуги прокрутки в TextBox(редагованому текстовому елементі), використовуйте ScrollViewerдодані властивості:

<TextBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
         ScrollViewer.VerticalScrollBarVisibility="Auto" />

Допустимі значення для цих двох властивостей є Disabled, Auto, Hiddenі Visible.


2
Як це зробити у дизайнера?
Bab Yogoo

16
Вибачте, я не впевнений, я не використовую дизайнера WPF. Я думаю, що якщо ви додасте XAML безпосередньо, дизайнер оновить себе.
Дрю Ноакс

5
@conqenator TextBox.ScrollToEnd ();
Petey B

2
@Greg, мова йде про TextBlockНЕ TextBox.
Дрю Ноакс

7
Іноді MaxHeight на Scrollviewer потрібен для того, щоб примусити сколот з'являтися, якщо елемент, що охоплює, не виконує жодної висоти.
HackerBaloo

106

Ви можете використовувати наступне:

<TextBox Name="myTextBox" 
         ScrollViewer.HorizontalScrollBarVisibility="Auto"
         ScrollViewer.VerticalScrollBarVisibility="Auto"
         ScrollViewer.CanContentScroll="True">SOME TEXT
</TextBox>

19
@jjnguy, я інтерпретував оригінальне запитання як про TextBlockне TextBox(як у заголовку та рядку відкриття), а у другому абзаці TextBox. Щоб було зрозуміло, ця відповідь, безумовно, найкращий підхід для текстових полів , і моя найкраща, яку я знаю для текстових блоків :)
Дрю Ноакс

@Drew, ах, має сенс. Дякуємо за роз’яснення.
jjnguy

2
Краще працювали і для мене. Принаймні, для TextBox при використанні навколо нього ScrollViewer, як і у прийнятій відповіді, межі TextBox зникають, оскільки весь елемент управління прокручується, а не лише його вміст.
Заправляється

20

Щось краще було б:

<Grid Width="Your-specified-value" >
    <ScrollViewer>
         <TextBlock Width="Auto" TextWrapping="Wrap" />
    </ScrollViewer>
</Grid>

Це гарантує, що текст у вашому текстовому блоці не переповнює та не перекриває елементи під текстовим блоком, як це може бути, якщо ви не використовуєте сітку. Це сталося зі мною, коли я спробував інші рішення, хоча текстовий блок вже був у сітці з іншими елементами. Майте на увазі, що ширина текстового блоку повинна бути Автоматична, і ви повинні вказати бажане в елементі Grid. Я це зробив у своєму коді, і це прекрасно працює. HTH.


7
<ScrollViewer Height="239" VerticalScrollBarVisibility="Auto">
    <TextBox AcceptsReturn="True" TextWrapping="Wrap" LineHeight="10" />
</ScrollViewer>

Це спосіб використовувати прокручуваний TextBox в XAML і використовувати його як текстову область.


1
Питання пов'язане з TextBlockне TextBox.
Афзаал Ахмад Зеешан

Не зовсім правильна відповідь, але я вважав, що VerticalScrollBarVisibility є корисною підказкою, тому +1
Малахій

4

Ця відповідь описує рішення з використанням MVVM.

Це рішення чудово, якщо ви хочете додати вікно журналу до вікна, яке автоматично прокручується донизу щоразу, коли додається нове повідомлення журналу.

Як тільки ці додані властивості будуть додані, їх можна буде використовувати повторно в будь-якому місці, тому це створює дуже модульне та багаторазове використання програмного забезпечення.

Додайте цей XAML:

<TextBox IsReadOnly="True"   
         Foreground="Gainsboro"                           
         FontSize="13" 
         ScrollViewer.HorizontalScrollBarVisibility="Auto"
         ScrollViewer.VerticalScrollBarVisibility="Auto"
         ScrollViewer.CanContentScroll="True"
         attachedBehaviors:TextBoxApppendBehaviors.AppendText="{Binding LogBoxViewModel.AttachedPropertyAppend}"                                       
         attachedBehaviors:TextBoxClearBehavior.TextBoxClear="{Binding LogBoxViewModel.AttachedPropertyClear}"                                    
         TextWrapping="Wrap">

Додати цю додану властивість:

public static class TextBoxApppendBehaviors
{
    #region AppendText Attached Property
    public static readonly DependencyProperty AppendTextProperty =
        DependencyProperty.RegisterAttached(
            "AppendText",
            typeof (string),
            typeof (TextBoxApppendBehaviors),
            new UIPropertyMetadata(null, OnAppendTextChanged));

    public static string GetAppendText(TextBox textBox)
    {
        return (string)textBox.GetValue(AppendTextProperty);
    }

    public static void SetAppendText(
        TextBox textBox,
        string value)
    {
        textBox.SetValue(AppendTextProperty, value);
    }

    private static void OnAppendTextChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        if (args.NewValue == null)
        {
            return;
        }

        string toAppend = args.NewValue.ToString();

        if (toAppend == "")
        {
            return;
        }

        TextBox textBox = d as TextBox;
        textBox?.AppendText(toAppend);
        textBox?.ScrollToEnd();
    }
    #endregion
}

І до цього вкладеного властивості (для очищення поля):

public static class TextBoxClearBehavior
{
    public static readonly DependencyProperty TextBoxClearProperty =
        DependencyProperty.RegisterAttached(
            "TextBoxClear",
            typeof(bool),
            typeof(TextBoxClearBehavior),
            new UIPropertyMetadata(false, OnTextBoxClearPropertyChanged));

    public static bool GetTextBoxClear(DependencyObject obj)
    {
        return (bool)obj.GetValue(TextBoxClearProperty);
    }

    public static void SetTextBoxClear(DependencyObject obj, bool value)
    {
        obj.SetValue(TextBoxClearProperty, value);
    }

    private static void OnTextBoxClearPropertyChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        if ((bool)args.NewValue == false)
        {
            return;
        }

        var textBox = (TextBox)d;
        textBox?.Clear();
    }
}   

Тоді, якщо ви використовуєте рамку введення залежності, наприклад MEF, ви можете помістити весь код, що входить до журналу, у його власний ViewModel:

public interface ILogBoxViewModel
{
    void CmdAppend(string toAppend);
    void CmdClear();

    bool AttachedPropertyClear { get; set; }

    string AttachedPropertyAppend { get; set; }
}

[Export(typeof(ILogBoxViewModel))]
public class LogBoxViewModel : ILogBoxViewModel, INotifyPropertyChanged
{
    private readonly ILog _log = LogManager.GetLogger<LogBoxViewModel>();

    private bool _attachedPropertyClear;
    private string _attachedPropertyAppend;

    public void CmdAppend(string toAppend)
    {
        string toLog = $"{DateTime.Now:HH:mm:ss} - {toAppend}\n";

        // Attached properties only fire on a change. This means it will still work if we publish the same message twice.
        AttachedPropertyAppend = "";
        AttachedPropertyAppend = toLog;

        _log.Info($"Appended to log box: {toAppend}.");
    }

    public void CmdClear()
    {
        AttachedPropertyClear = false;
        AttachedPropertyClear = true;

        _log.Info($"Cleared the GUI log box.");
    }

    public bool AttachedPropertyClear
    {
        get { return _attachedPropertyClear; }
        set { _attachedPropertyClear = value; OnPropertyChanged(); }
    }

    public string AttachedPropertyAppend
    {
        get { return _attachedPropertyAppend; }
        set { _attachedPropertyAppend = value; OnPropertyChanged(); }
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

Ось як це працює:

  • ViewModel перемикає вкладені властивості для управління TextBox.
  • Оскільки використовується "Додавати", це блискавично.
  • Будь-який інший ViewModel може генерувати повідомлення з журналом, викликаючи методи в журналі ViewModel.
  • Оскільки ми використовуємо вбудований у TextBox ScrollViewer, ми можемо змусити його автоматично прокручувати донизу текстового поля щоразу, коли додається нове повідомлення.

4
<ScrollViewer MaxHeight="50"  
              Width="Auto" 
              HorizontalScrollBarVisibility="Disabled"
              VerticalScrollBarVisibility="Auto">
     <TextBlock Text="{Binding Path=}" 
                Style="{StaticResource TextStyle_Data}" 
                TextWrapping="Wrap" />
</ScrollViewer>

Я роблю це по-іншому, додаючи MaxHeight у ScrollViewer.

Просто налаштуйте MaxHeight, щоб відображати більше чи менше рядків тексту. Легко.



1

Я намагався змусити ці пропозиції працювати над текстовим блоком, але не зміг його працювати. Я навіть намагався змусити його працювати у дизайнера. (Подивіться у макеті та розгорніть список, натиснувши стрілку вниз "V" внизу) Я спробував встановити прокручувальний переглядач на Visible, а потім Auto , але він все одно не працюватиме.

Зрештою я відмовився і змінив TextBlockна набір TextBoxз атрибутом Readonly , і це спрацювало як шарм.


0

Не знаю , якщо хто - то має цю проблему , але обгортання мою TextBlockв ScrollViewersomewhow переплуталися мій UI - як просте рішення , я зрозумів, що заміна TextBlockна TextBoxяк цей

<TextBox  Name="textBlock" SelectionBrush="Transparent" Cursor="Arrow" IsReadOnly="True" Text="My Text" VerticalScrollBarVisibility="Auto">

створює TextBoxте, що виглядає і поводиться як TextBlockіз смугою прокрутки (і все це можна зробити в дизайнері).


0

Це просте рішення цього питання. Вертикальна прокрутка активується лише тоді, коли текст переповнюється.

<TextBox Text="Try typing some text here " ScrollViewer.VerticalScrollBarVisibility="Auto" TextWrapping="WrapWithOverflow" />

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.