Thanh cuộn dọc tự động trong WPF TextBlock?


335

Tôi có một TextBlockWPF. Tôi viết nhiều dòng cho nó, vượt xa chiều cao của nó. Tôi dự kiến ​​một thanh cuộn dọc sẽ tự động xuất hiện khi điều đó xảy ra, nhưng nó đã không xảy ra. Tôi đã cố gắng tìm kiếm một thuộc tính thanh cuộn trong ngăn Thuộc tính, nhưng không thể tìm thấy thuộc tính.

Làm cách nào tôi có thể tạo thanh cuộn dọc được tạo tự động cho TextBlocknội dung của mình khi nội dung của nó vượt quá chiều cao của nó?

Làm rõ: Tôi thà làm điều đó từ nhà thiết kế chứ không phải bằng cách viết trực tiếp cho XAML.


1
Khi đọc lại câu hỏi này, tôi nhận thấy bạn đề cập TextBlockhai lần và TextBoxmột lần.
vẽ Noakes

Câu trả lời:


554

Gói nó trong một trình xem cuộn:

<ScrollViewer>
    <TextBlock />
</ScrollViewer>

LƯU Ý câu trả lời này áp dụng cho một TextBlock(phần tử văn bản chỉ đọc) như được yêu cầu trong câu hỏi ban đầu.

Nếu bạn muốn hiển thị các thanh cuộn trong một TextBox(phần tử văn bản có thể chỉnh sửa) thì hãy sử dụng các ScrollViewerthuộc tính đính kèm:

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

Giá trị hợp lệ cho hai thuộc tính đó là Disabled, Auto, HiddenVisible.


2
Làm thế nào để tôi làm điều đó từ các nhà thiết kế?
Bab Yogoo

16
Xin lỗi tôi không chắc chắn, tôi không sử dụng trình thiết kế WPF. Tôi nghĩ rằng nếu bạn thêm XAML trực tiếp, nhà thiết kế sẽ tự cập nhật.
Drew Noakes

5
@conqenator TextBox.ScrollToEnd ();
Petey B

2
@Greg, câu hỏi là về TextBlockkhông TextBox.
vẽ Noakes

7
Đôi khi, cần có MaxHeight trên Scrollviewer để buộc scoll xuất hiện nếu phần tử kèm theo không thực thi bất kỳ chiều cao nào.
HackerBaloo

106

có thể sử dụng như sau

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

19
@jjnguy, tôi giải thích câu hỏi ban đầu là về TextBlockkhông TextBox(như trong tiêu đề và dòng mở đầu), nhưng đoạn thứ hai đã đề cập TextBox. Để rõ ràng, câu trả lời này chắc chắn là cách tiếp cận tốt nhất cho các hộp văn bản và của tôi là cách tốt nhất tôi biết về các khối văn bản :)
Drew Noakes

@Drew, ah, có ý nghĩa. Cảm ơn bạn đã làm rõ.
jjnguy

2
Làm việc tốt hơn cho tôi quá. Ít nhất là đối với TextBox, khi sử dụng ScrollViewer xung quanh nó, như trong câu trả lời được chấp nhận, các đường viền của TextBox sẽ biến mất, bởi vì toàn bộ điều khiển được cuộn và không chỉ nội dung của nó.
Cung cấp nhiên liệu vào

20

Một cái gì đó tốt hơn sẽ là:

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

Điều này đảm bảo rằng văn bản trong trình chặn văn bản của bạn không bị tràn và chồng lấp các thành phần bên dưới trình chặn văn bản như có thể là trường hợp nếu bạn không sử dụng lưới. Điều đó đã xảy ra với tôi khi tôi thử các giải pháp khác mặc dù textblock đã nằm trong một lưới với các yếu tố khác. Hãy nhớ rằng chiều rộng của trình chặn văn bản phải là Tự động và bạn nên chỉ định mong muốn trong phần tử Lưới. Tôi đã làm điều này trong mã của tôi và nó hoạt động rất đẹp. HTH.


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

Đây là cách để sử dụng TextBox cuộn trong XAML và sử dụng nó làm vùng văn bản.


1
Câu hỏi có liên quan đến TextBlockkhông TextBox.
Afzaal Ahmad Zeeshan

Câu trả lời không hoàn toàn chính xác, nhưng tôi thấy dọcScrollBarVisibility là một gợi ý hữu ích nên +1
Malachi

4

Câu trả lời này mô tả một giải pháp sử dụng MVVM.

Giải pháp này rất tuyệt nếu bạn muốn thêm hộp ghi nhật ký vào cửa sổ, nó sẽ tự động cuộn xuống phía dưới mỗi lần thêm thông điệp ghi nhật ký mới.

Khi các thuộc tính đính kèm này được thêm vào, chúng có thể được sử dụng lại ở bất cứ đâu, do đó, nó tạo ra phần mềm rất mô-đun và có thể tái sử dụng.

Thêm XAML này:

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

Thêm tài sản đính kèm này:

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
}

Và tài sản đính kèm này (để xóa hộp):

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

Sau đó, nếu bạn đang sử dụng khung tiêm phụ thuộc như MEF, bạn có thể đặt tất cả mã cụ thể ghi nhật ký vào ViewModel của riêng nó:

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
}

Đây là cách nó hoạt động:

  • ViewModel bật tắt các Thuộc tính được đính kèm để điều khiển TextBox.
  • Khi sử dụng "Nối", nó nhanh như chớp.
  • Bất kỳ ViewModel nào khác cũng có thể tạo thông điệp ghi nhật ký bằng cách gọi các phương thức trên ViewModel đăng nhập.
  • Khi chúng tôi sử dụng ScrollViewer được tích hợp trong TextBox, chúng tôi có thể làm cho nó tự động cuộn xuống dưới cùng của hộp văn bản mỗi khi một tin nhắn mới được thêm vào.

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

Tôi đang làm điều này theo một cách khác bằng cách đưa MaxHeight vào ScrollViewer.

Chỉ cần điều chỉnh MaxHeight để hiển thị nhiều hoặc ít dòng văn bản. Dễ dàng.



1

Tôi đã cố gắng để làm cho các đề xuất này hoạt động cho một textblock, nhưng không thể làm cho nó hoạt động. Tôi thậm chí đã cố gắng để nó làm việc từ nhà thiết kế. (Xem trong Bố cục và mở rộng danh sách bằng cách nhấp vào mũi tên xuống "V" ở dưới cùng) Tôi đã thử đặt trình xem cuộn thành Hiển thị và sau đó Tự động , nhưng nó vẫn không hoạt động.

Cuối cùng tôi đã từ bỏ và thay đổi TextBlockthành một TextBoxvới tập thuộc tính Readonly và nó hoạt động như một bùa mê.


0

Không biết có ai khác gặp phải vấn đề này không nhưng việc đưa tôi TextBlockvào một cách ScrollViewernào đó đã làm rối giao diện người dùng của tôi - như một cách giải quyết đơn giản tôi đã tìm ra rằng thay thế TextBlockbằng một cái TextBoxnhư thế này

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

tạo ra một giao TextBoxdiện trông giống như một TextBlockthanh cuộn (và bạn có thể làm tất cả trong trình thiết kế).


0

Đây là một giải pháp đơn giản cho câu hỏi đó. Cuộn dọc sẽ chỉ được kích hoạt khi văn bản tràn ra.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.