【问题标题】:Automatic vertical scroll bar in WPF TextBlock?WPF TextBlock中的自动垂直滚动条?
【发布时间】:2010-11-14 14:35:16
【问题描述】:

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

如果我的TextBlock 的内容超过了它的高度,如何自动创建垂直滚动条?

澄清:我宁愿从设计者那里完成,而不是直接写入 XAML。

【问题讨论】:

  • 重新阅读这个问题后,我注意到您提到了两次TextBlock 和一次TextBox

标签: c# .net wpf scrollbar textblock


【解决方案1】:

不知道其他人是否有此问题,但将我的 TextBlock 包装到 ScrollViewer 不知何故弄乱了我的 UI - 作为一个简单的解决方法,我发现用 TextBox 替换 TextBlock 就像这样

<TextBox  SelectionBrush="Transparent" 
          Cursor="Arrow" 
          IsReadOnly="True" 
          Text="{Binding Text}" 
          VerticalScrollBarVisibility="Auto">

创建一个TextBox,其外观和行为类似于带有滚动条的TextBlock(您可以在设计器中完成所有操作)。

【讨论】:

    【解决方案2】:

    我试图让这些建议适用于文本块,但无法让它发挥作用。我什至试图让它从设计师那里工作。 (查看布局并通过单击底部的向下箭头“V”来展开列表)我尝试将滚动查看器设置为 Visible,然后设置为 Auto,但它仍然不会不行。

    我最终放弃了,将 TextBlock 更改为带有 Readonly 属性集的 TextBox,它就像一个魅力。

    【讨论】:

      【解决方案3】:

      这是该问题的简单解决方案。只有在文本溢出时才会激活垂直滚动。

      &lt;TextBox Text="Try typing some text here " ScrollViewer.VerticalScrollBarVisibility="Auto" TextWrapping="WrapWithOverflow" /&gt;

      【讨论】:

        【解决方案4】:
        <ScrollViewer MaxHeight="50"  
                      Width="Auto" 
                      HorizontalScrollBarVisibility="Disabled"
                      VerticalScrollBarVisibility="Auto">
             <TextBlock Text="{Binding Path=}" 
                        Style="{StaticResource TextStyle_Data}" 
                        TextWrapping="Wrap" />
        </ScrollViewer>
        

        我通过将 MaxHeight 放入 ScrollViewer 以另一种方式做到这一点。

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

        【讨论】:

          【解决方案5】:
          <ScrollViewer Height="239" VerticalScrollBarVisibility="Auto">
              <TextBox AcceptsReturn="True" TextWrapping="Wrap" LineHeight="10" />
          </ScrollViewer>
          

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

          【讨论】:

          • 该问题与TextBlock 不是TextBox 有关。
          • 不是很正确的答案,但我发现 VerticalScrollBarVisibility 是一个有用的提示,所以 +1
          【解决方案6】:

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

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

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

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

          还有这个附加属性(清除框):

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

          然后,如果您使用 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 都可以通过调用日志 ViewModel 上的方法来生成日志消息。
          • 当我们使用 TextBox 中内置的 ScrollViewer 时,我们可以让它在每次添加新消息时自动滚动到文本框的底部。

          【讨论】:

            【解决方案7】:

            你可以使用

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

            这些是 wpf 的附加属性。 欲了解更多信息

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

            【讨论】:

              【解决方案8】:

              更好的是:

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

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

              【讨论】:

                【解决方案9】:

                现在可以使用以下内容:

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

                【讨论】:

                • @jjnguy,我将原始问题解释为关于TextBlock 而不是TextBox(如标题和开头行),但第二段提到了TextBox。需要明确的是,这个答案绝对是文本 boxes 的最佳方法,而我的答案是我所知道的文本 blocks 的最佳方法 :)
                • @Drew,啊,有道理。感谢您的澄清。
                • 对我来说也更好。至少对于一个 TextBox,当在它周围使用 ScrollViewer 时,就像在接受的答案中一样,TextBox 的边框会消失,因为整个控件都会滚动,而不仅仅是它的内容。
                【解决方案10】:

                将其包装在滚动查看器中:

                <ScrollViewer>
                    <TextBlock />
                </ScrollViewer>
                

                注意此答案适用于原始问题中要求的TextBlock(只读文本元素)。

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

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

                这两个属性的有效值为DisabledAutoHiddenVisible

                【讨论】:

                • 设计师怎么做?
                • 对不起,我不确定,我不使用 WPF 设计器。我认为如果您直接添加 XAML,设计器会自行更新。
                • @conqenator TextBox.ScrollToEnd();
                • @Greg,问题是关于TextBlock 而不是TextBox
                • 如果封闭元素不强制任何高度,有时需要在 Scrollviewer 上设置 MaxHeight 来强制显示 scoll。
                猜你喜欢
                • 2015-07-01
                • 2011-08-03
                • 1970-01-01
                • 1970-01-01
                • 2023-03-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多