首页 文章

WPF TextBlock中的自动垂直滚动条?

提问于
浏览
287

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

一旦内容超出其高度,如何为我的 TextBlock 自动创建垂直滚动条?

澄清:我宁愿从设计师那里做,而不是直接写给XAML .

10 回答

  • 3

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

    <ScrollViewer>
        <TextBlock />
    </ScrollViewer>
    

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

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

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

    这两个属性的有效值为 DisabledAutoHiddenVisible .

  • 0

    现在可以使用以下内容:

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

    更好的是:

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

    这样可以确保文本块中的文本不会溢出并重叠文本块下面的元素,如果不使用网格则可能会出现这种情况 . 当我尝试其他解决方案时,即使文本块已经在其他元素的网格中,这也发生在我身上 . 请记住,文本块的宽度应为“自动”,您应在Grid元素中指定所需的宽度 . 我在我的代码中做到了这一点,它的工作非常精彩 . HTH .

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

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

  • 3

    这个答案描述了使用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切换附加属性以控制TextBox .

    • 因为它闪电般快速 .

    • 任何其他ViewModel都可以通过调用日志记录ViewModel上的方法来生成日志记录消息 .

    • 当我们使用TextBox中内置的ScrollViewer时,我们可以在每次添加新消息时自动滚动到文本框的底部 .

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

    我通过将MaxHeight放在ScrollViewer中以另一种方式执行此操作 .

    只需调整MaxHeight即可显示更多或更少的文本行 . 简单 .

  • 96

    您可以使用

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

    这些是wpf的附加属性 . 欲获得更多信息

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

  • 0

    我试图将这些建议用于文本块,但无法使其工作 . 我甚至试图从设计师那里得到它 . (查看布局并通过单击底部的向下箭头"V"展开列表)我尝试将scrollviewer设置为 Visible 然后 Auto ,但它仍然无效 .

    我最终放弃了并将 TextBlock 更改为 TextBox 并设置了 Readonly 属性,它就像一个魅力 .

  • 19

    不知道是否有其他人有这个问题,但将我的 TextBlock 包装成 ScrollViewer 某些人搞砸了我的用户界面 - 作为一个简单的解决方法我发现用 TextBox 替换 TextBlock 就像这个

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

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

  • 2

    这是该问题的简单解决方案 . 仅当文本溢出时才会激活垂直滚动 .

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

相关问题