c# Barra di scorrimento verticale automatica in TextBlock WPF?



.net scrollbar (6)

Ho un TextBlock in WPF. Scrivo molte righe, superando di gran lunga la sua altezza verticale. Mi aspettavo che una barra di scorrimento verticale appaia automaticamente quando ciò accade, ma non è così. Ho provato a cercare una proprietà della barra di scorrimento nel riquadro Proprietà, ma non sono riuscito a trovarne una.

Come posso creare una barra di scorrimento verticale creata automaticamente per il mio TextBlock quando il suo contenuto supera la sua altezza?

Chiarimento: preferirei farlo dal designer e non scrivendo direttamente su XAML.

https://src-bin.com


Answer #1

Avvolgilo in un visualizzatore di scorrimento:

<ScrollViewer>
    <TextBlock />
</ScrollViewer>

NOTA questa risposta si applica a un TextBlock (un elemento di testo di sola lettura) come richiesto nella domanda originale.

Se si desidera mostrare le barre di scorrimento in un TextBox (un elemento di testo modificabile), utilizzare le proprietà associate a ScrollViewer :

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

I valori validi per queste due proprietà sono Disabled , Auto , Hidden e Visible .


Answer #2

Non so se qualcun altro ha questo problema, ma avvolgere il mio TextBlock in un ScrollViewer qualche modo ha incasinato la mia interfaccia utente - come una soluzione semplice ho capito che sostituire il TextBlock con un TextBox come questo

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

crea un TextBox che assomiglia e si comporta come un TextBlock con una barra di scorrimento (e puoi farlo tutto nella finestra di progettazione).


Answer #3

Qualcosa di meglio sarebbe:

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

Ciò garantisce che il testo nel blocco di testo non si sovrapponga e si sovrapponga agli elementi sotto il blocco di testo, come potrebbe essere il caso se non si utilizza la griglia. Questo è successo a me quando ho provato altre soluzioni anche se il blocco di testo era già in una griglia con altri elementi. Tieni presente che la larghezza del blocco di testo dovrebbe essere Auto e dovresti specificare il desiderato con l'elemento Grid. L'ho fatto nel mio codice e funziona magnificamente. HTH.


Answer #4

Questa risposta descrive una soluzione utilizzando MVVM.

Questa soluzione è ottima se si desidera aggiungere una finestra di registrazione a una finestra, che scorre automaticamente verso il basso ogni volta che viene aggiunto un nuovo messaggio di registrazione.

Una volta aggiunte queste proprietà, queste possono essere riutilizzate ovunque, quindi è un software molto modulare e riutilizzabile.

Aggiungi questo 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">

Aggiungi questa proprietà allegata:

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
}

E questa proprietà allegata (per cancellare la scatola):

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

Quindi, se si utilizza un framework di integrazione delle dipendenze come MEF, è possibile inserire tutto il codice di registrazione specifico nel proprio 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
}

Ecco come funziona:

  • ViewModel attiva le Proprietà collegate per controllare il TextBox.
  • Poiché usa "Aggiungi", è veloce come un fulmine.
  • Qualsiasi altro ViewModel può generare messaggi di registrazione chiamando metodi sul ViewModel di registrazione.
  • Usando ScrollViewer integrato nel TextBox, possiamo farlo scorrere automaticamente fino alla fine della casella di testo ogni volta che viene aggiunto un nuovo messaggio.

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

Questo è il modo di usare il TextBox scorrevole in XAML e usarlo come area di testo.


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

Lo faccio in un altro modo inserendo MaxHeight in ScrollViewer.

Basta regolare l'altezza massima per mostrare più o meno righe di testo. Facile.





textblock