Bilah gulir vertikal otomatis di WPF TextBlock?

336

Saya punya TextBlockdi WPF. Saya menulis banyak baris untuk itu, jauh melebihi ketinggian vertikal. Saya mengharapkan bilah gulir vertikal muncul secara otomatis ketika itu terjadi, tetapi ternyata tidak. Saya mencoba mencari properti bilah gulir di panel Properti, tetapi tidak dapat menemukannya.

Bagaimana cara membuat bilah gulir vertikal yang dibuat secara otomatis untuk saya TextBlocksetelah isinya melebihi ketinggiannya?

Klarifikasi: Saya lebih suka melakukannya dari desainer dan bukan dengan langsung menulis ke XAML.

Bab Yogoo
sumber
1
Setelah membaca kembali pertanyaan ini, saya perhatikan Anda menyebutkan TextBlockdua kali dan TextBoxsatu kali.
Drew Noakes

Jawaban:

555

Bungkus dalam penampil gulir:

<ScrollViewer>
    <TextBlock />
</ScrollViewer>

CATATAN jawaban ini berlaku untuk TextBlock(elemen teks hanya baca) seperti yang diminta dalam pertanyaan asli.

Jika Anda ingin menampilkan bilah gulir di TextBox(elemen teks yang dapat diedit) maka gunakan ScrollViewerproperti terlampir:

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

Nilai yang valid untuk dua sifat ini Disabled, Auto, Hiddendan Visible.

Drew Noakes
sumber
2
Bagaimana saya melakukannya dari desainer?
Bab Yogoo
16
Maaf saya tidak yakin, saya tidak menggunakan desainer WPF. Saya pikir jika Anda menambahkan XAML secara langsung, perancang akan memperbarui sendiri.
Drew Noakes
5
@conqenator TextBox.ScrollToEnd ();
Petey B
2
@ Greg, pertanyaannya adalah tentang TextBlocktidak TextBox.
Drew Noakes
7
Terkadang MaxHeight pada Scrollviewer diperlukan untuk memaksa scoll muncul jika elemen penutup tidak memaksakan ketinggian apa pun.
HackerBaloo
106

dapat menggunakan yang berikut ini sekarang:

<TextBox Name="myTextBox" 
         ScrollViewer.HorizontalScrollBarVisibility="Auto"
         ScrollViewer.VerticalScrollBarVisibility="Auto"
         ScrollViewer.CanContentScroll="True">SOME TEXT
</TextBox>
vince
sumber
19
@ jjnguy, saya menafsirkan pertanyaan asli sebagai tentang TextBlockbukan TextBox(seperti pada judul dan kalimat pembuka), tetapi paragraf kedua disebutkan TextBox. Untuk lebih jelasnya, jawaban ini jelas merupakan pendekatan terbaik untuk kotak teks , dan milik saya adalah yang terbaik yang saya ketahui untuk blok teks :)
Drew Noakes
@Drew, ah, masuk akal. Terimakasih atas klarifikasinya.
jjnguy
2
Bekerja lebih baik untuk saya juga. Setidaknya untuk TextBox, ketika menggunakan ScrollViewer di sekitarnya, seperti pada jawaban yang diterima, batas TextBox 'menghilang, karena seluruh kontrol digulir, dan tidak hanya isinya.
Dipicu
20

Sesuatu yang lebih baik adalah:

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

Ini memastikan bahwa teks dalam blokir teks Anda tidak meluap dan tumpang tindih elemen di bawah blokir teks seperti yang mungkin terjadi jika Anda tidak menggunakan kisi. Itu terjadi pada saya ketika saya mencoba solusi lain meskipun blok teks sudah di grid dengan elemen lain. Ingatlah bahwa lebar blokir teks haruslah Otomatis dan Anda harus menentukan yang diinginkan dengan elemen Grid. Saya melakukan ini dalam kode saya dan itu bekerja dengan indah. HTH.

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

Ini adalah cara untuk menggunakan TextBox scrolling di XAML dan menggunakannya sebagai area teks.

John
sumber
1
Pertanyaannya terkait dengan TextBlocktidak TextBox.
Afzaal Ahmad Zeeshan
Tidak cukup jawaban yang benar, tetapi saya menemukan VerticalScrollBarVisibility menjadi petunjuk yang bermanfaat sehingga +1
Maleakhi
4

Jawaban ini menjelaskan solusi menggunakan MVVM.

Solusi ini sangat bagus jika Anda ingin menambahkan kotak logging ke jendela, yang secara otomatis akan menggulir ke bawah setiap kali pesan logging baru ditambahkan.

Setelah properti terlampir ini ditambahkan, mereka dapat digunakan kembali di mana saja, sehingga membuatnya untuk perangkat lunak yang sangat modular dan dapat digunakan kembali.

Tambahkan XAML ini:

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

Tambahkan properti terlampir ini:

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
}

Dan properti terlampir ini (untuk menghapus kotak):

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

Kemudian, jika Anda menggunakan kerangka kerja injeksi ketergantungan seperti MEF, Anda dapat menempatkan semua kode khusus logging ke dalam ViewModel itu sendiri:

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
}

Begini cara kerjanya:

  • ViewModel mengaktifkan Properti Terlampir untuk mengontrol TextBox.
  • Karena menggunakan "Tambah", itu cepat kilat.
  • ViewModel lainnya dapat menghasilkan pesan logging dengan memanggil metode pada ViewModel logging.
  • Ketika kita menggunakan ScrollViewer yang dibangun di dalam TextBox, kita dapat membuatnya secara otomatis gulir ke bagian bawah kotak teks setiap kali pesan baru ditambahkan.
Contango
sumber
4
<ScrollViewer MaxHeight="50"  
              Width="Auto" 
              HorizontalScrollBarVisibility="Disabled"
              VerticalScrollBarVisibility="Auto">
     <TextBlock Text="{Binding Path=}" 
                Style="{StaticResource TextStyle_Data}" 
                TextWrapping="Wrap" />
</ScrollViewer>

Saya melakukan ini dengan cara lain dengan meletakkan MaxHeight di ScrollViewer.

Cukup Sesuaikan MaxHeight untuk menampilkan lebih banyak atau lebih sedikit baris teks. Mudah.

Tony Wu
sumber
1

Saya mencoba agar saran ini berfungsi untuk blokir teks, tetapi tidak berhasil. Saya bahkan mencoba membuatnya bekerja dari perancang. (Lihat Layout dan perluas daftar dengan mengklik panah bawah "V" di bagian bawah) Saya mencoba mengatur scrollviewer ke Visible dan kemudian Auto , tetapi masih tidak berfungsi.

Saya akhirnya menyerah dan mengubah TextBlockke TextBoxdengan set atribut Readonly , dan itu bekerja seperti pesona.

Scott Bordelon
sumber
0

Tidak tahu apakah ada orang lain yang memiliki masalah ini, tetapi membungkus saya TextBlockdengan ScrollViewerentah bagaimana mengacaukan UI saya - sebagai solusi sederhana saya menemukan bahwa mengganti TextBlockdengan yang TextBoxseperti ini

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

menciptakan TextBoxyang terlihat dan berperilaku seperti TextBlockdengan bilah gulir (dan Anda dapat melakukan semuanya di perancang).

dunkleosteus
sumber
0

Ini adalah solusi sederhana untuk pertanyaan itu. Gulir vertikal akan diaktifkan hanya ketika teks meluap.

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

Zuhair
sumber