2009-07-28 59 views
265

我在WPF中有一个TextBlock。我写了很多行,远远超过它的垂直高度。我期望一个垂直滚动条在这种情况发生时自动出现,但它没有。我试图在“属性”窗格中查找滚动条属性,但找不到一个属性。WPF TextBlock中的自动垂直滚动条?

一旦其内容超过其高度,我怎样才能为我的TextBlock自动创建垂直滚动条?

说明:我宁愿从设计师那里做,而不是直接写给XAML。

+0

在重新阅读这个问题时,我发现你提到过两次`TextBlock`和`TextBox`一次。 – 2011-03-25 12:51:30

回答

446

包装在一个滚动浏览器:

<ScrollViewer> 
    <TextBlock /> 
</ScrollViewer> 

注意这个答案适用于TextBlock(只读文本元素)的要求在原来的问题。

如果你想显示在TextBox(可编辑的文本元素)滚动条,然后用ScrollViewer附加属性:

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

对于这两个属性的有效值是DisabledAutoHiddenVisible

+2

我如何从设计师那里做到这一点? – 2009-07-28 07:19:31

+14

抱歉,我不确定,我没有使用WPF设计器。我想如果你直接添加XAML,设计师会自行更新。 – 2009-07-28 08:04:07

+5

@conqenator TextBox.ScrollToEnd(); – 2011-02-04 18:51:40

89

可以使用现在以下几点:

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

东西更好的方式是:

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

这可以确保在你的文本块中的文本不溢出,并为可能重叠的文本块下面的元素如果你不使用网格就是这种情况。即使文本块已经在其他元素的网格中,我也尝试了其他解决方案时发生在我身上。请记住,textblock的宽度应该是Auto,并且您应该在Grid元素中指定所需的值。我在我的代码中做到了这一点,并且它的工作非常好。 HTH。

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

这是在XAML中使用滚动文本框并将其用作文本区域的方法。

3

这个答案描述了使用MVVM的解决方案。

如果您想将日志框添加到窗口中,每次添加新的日志消息时都会自动滚动到底部,此解决方案非常棒。

一旦添加了这些附加属性,它们可以在任何地方重复使用,因此它可以生成非常模块化和可重用的软件。,

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

然后,如果你”:

添加此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 
} 

而这种附加属性(以清除框)重新使用依赖注入框架(如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都可以通过调用日志ViewModel上的方法来生成日志消息。
  • 由于我们使用内置到TextBox中的ScrollViewer,每次添加新消息时,我们都可以自动滚动到文本框的底部。
3
<ScrollViewer MaxHeight="50" 
       Width="Auto" 
       HorizontalScrollBarVisibility="Disabled" 
       VerticalScrollBarVisibility="Auto"> 
    <TextBlock Text="{Binding Path=}" 
       Style="{StaticResource TextStyle_Data}" 
       TextWrapping="Wrap" /> 
</ScrollViewer> 

我以另一种方式通过将MaxHeight在ScrollViewer中这样做。

只需调整MaxHeight以显示更多或更少的文本行。简单。