it-swarm.com.de

Automatische vertikale Bildlaufleiste in WPF TextBlock?

Ich habe eine TextBlock in WPF. Ich schreibe viele Zeilen hinein, die seine vertikale Höhe weit überschreiten. Ich habe erwartet, dass in diesem Fall automatisch eine vertikale Bildlaufleiste angezeigt wird. Dies ist jedoch nicht der Fall. Ich habe versucht, im Eigenschaftenbereich nach einer Bildlaufleisten-Eigenschaft zu suchen, konnte aber keine finden.

Wie kann ich eine vertikale Bildlaufleiste erstellen, die automatisch für mein _ TextBlock erstellt wird, wenn der Inhalt die Höhe überschreitet?

Klarstellung: Ich würde es lieber vom Designer machen und nicht direkt in die XAML schreiben.

294
Bab Yogoo

Wickeln Sie es in einen Scroll-Viewer:

<ScrollViewer>
    <TextBlock />
</ScrollViewer>

NOTEDiese Antwort gilt für ein TextBlock (ein schreibgeschütztes Textelement), wie in der ursprünglichen Frage verlangt.

Wenn Sie Bildlaufleisten in einer TextBox (einem bearbeitbaren Textelement) anzeigen möchten, verwenden Sie die angefügten ScrollViewer-Eigenschaften:

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

Gültige Werte für diese beiden Eigenschaften sind Disabled, Auto, Hidden und Visible.

501
Drew Noakes

kann jetzt folgendes verwenden:

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

Etwas Besseres wäre:

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

Dadurch wird sichergestellt, dass der Text in Ihrem Textblock nicht überläuft und die Elemente unter dem Textblock überlappt, wie es der Fall sein kann, wenn Sie das Raster nicht verwenden. Das passierte mir, als ich andere Lösungen ausprobierte, obwohl der Textblock bereits in einem Raster mit anderen Elementen war. Beachten Sie, dass die Breite des Textblocks Auto sein sollte und Sie im Element Grid die gewünschte Breite angeben möchten. Ich habe das in meinem Code gemacht und es funktioniert wunderbar. HTH.

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

Auf diese Weise können Sie die Bildlauf-TextBox in XAML als Textbereich verwenden.

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

Ich mache das auf andere Weise, indem ich MaxHeight in ScrollViewer einfüge.

Passen Sie einfach das MaxHeight an, um mehr oder weniger Textzeilen anzuzeigen. Einfach.

3
Tony Wu

Diese Antwort beschreibt eine Lösung, die MVVM verwendet.

Diese Lösung eignet sich hervorragend, wenn Sie einem Fenster ein Protokollierungsfenster hinzufügen möchten, das bei jedem Hinzufügen einer neuen Protokollierungsnachricht automatisch nach unten scrollen soll.

Sobald diese angefügten Eigenschaften hinzugefügt wurden, können sie überall wiederverwendet werden, so dass eine sehr modulare und wiederverwendbare Software entsteht.

Fügen Sie diese XAML hinzu:

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

Fügen Sie diese angefügte Eigenschaft hinzu:

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
}

Und diese angefügte Eigenschaft (um das Kästchen zu löschen):

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

Wenn Sie ein Abhängigkeitsinjektions-Framework wie MEF verwenden, können Sie den gesamten protokollspezifischen Code in sein eigenes ViewModel einfügen:

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
}

So funktioniert das:

  • Das ViewModel schaltet die angefügten Eigenschaften um, um das Textfeld zu steuern.
  • Da es "Anhängen" verwendet, ist es blitzschnell.
  • Jedes andere ViewModel kann Protokollierungsnachrichten generieren, indem Methoden für das Protokollierungs-ViewModel aufgerufen werden.
  • Da wir den in die TextBox integrierten ScrollViewer verwenden, können Sie ihn bei jedem Hinzufügen einer neuen Nachricht automatisch zum unteren Rand der Textbox scrollen lassen.
3
Contango

Sie können verwenden

ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollBarVisibility="Visible"

Diese sind angehängte Eigenschaft von wpf . Weitere Informationen

http://wpfbugs.blogspot.in/2014/02/wpf-layout-controls-scrollviewer.html

2
ravi saini

Ich habe versucht, diese Vorschläge für einen Textblock zu verwenden, konnte ihn aber nicht zum Laufen bringen. Ich habe sogar versucht, es vom Designer zum Laufen zu bringen. (Schauen Sie in Layout und erweitern Sie die Liste, indem Sie auf den Abwärtspfeil "V" unten klicken). Ich habe versucht, den Scrollviewer auf Visible und dann Auto zu setzen, aber es funktioniert trotzdem nicht. 

Ich gab schließlich auf und änderte die TextBlock in eine TextBox mit demReadonlyAttribut-Set, und es funktionierte wie ein Zauber. 

1
Scott Bordelon

Ich weiß nicht, ob jemand anderes dieses Problem hat, aber meine TextBlock in eine ScrollViewer einhüllt, die meine Benutzeroberfläche durcheinanderbringt - als einfache Problemumgehung habe ich herausgefunden, dass die TextBlock durch eine TextBox wie diese ersetzt wird

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

erstellt eine TextBox, die wie eine TextBlock mit einer Bildlaufleiste aussieht und sich verhält (und Sie können dies alles im Designer tun).

0
dunkleosteus

Dies ist eine einfache Lösung für diese Frage. Der vertikale Bildlauf wird nur aktiviert, wenn der Text überläuft.

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

0
Zuhair