在 WPF 中显示一段文本

发布于 2025-01-02 20:11:58 字数 3114 浏览 1 评论 0原文

我有一个准系统的 WPF 应用程序,它有大约 1 兆的 ASCII 文本要显示。我最初将 TextBlock 放在 ScrollViewer 的 WrapPanel 中。当我调整窗口大小时,它正确地滚动并调整大小,但速度非常慢!我需要更快的东西。

因此,我将文本放入 FormattedText 中,并使用自定义控件呈现该文本。这速度快得多,但没有调整大小。所以我调整了自定义控件的大小。但每秒重绘次数太多,所以我只每 100 毫秒重绘一次。

好多了。渲染和调整大小仍然不是很好,但比以前好多了。但我失去了滚动。

最终我需要一个能做很多事情的解决方案 - 但现在我正在尝试有一个能做一点事情的解决方案:显示文本内存、换行、有滚动条并且高性能。最终,我希望它能够缩放到一大段文本,具有内联颜色,部分文本的一些鼠标悬停/单击事件...

我怎样才能使FormattedText(或者更准确地说,DrawingVisual)具有垂直滚动条?

这是我的 FrameworkElement,显示了我的 FormattedText:

using System;
using System.Windows;
using System.Windows.Media;

namespace Recall
{
    public class LightweightTextBox : FrameworkElement
    {
        private VisualCollection _children;
        private FormattedText _formattedText;
        private System.Threading.Timer _resizeTimer;
        private const int _resizeDelay = 100;

        public double MaxTextWidth
        {
            get { return this._formattedText.MaxTextWidth; }
            set { this._formattedText.MaxTextWidth = value; }
        }

        public LightweightTextBox(FormattedText formattedText)
        {
            this._children = new VisualCollection(this);
            this._formattedText = formattedText;

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();
            drawingContext.DrawText(this._formattedText, new Point(0, 0));
            drawingContext.Close();
            _children.Add(drawingVisual);

            this.SizeChanged += new SizeChangedEventHandler(LightweightTextBox_SizeChanged);
        }

        void LightweightTextBox_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.MaxTextWidth = e.NewSize.Width;

            if (_resizeTimer != null)
                _resizeTimer.Change(_resizeDelay, System.Threading.Timeout.Infinite);
            else
                _resizeTimer = new System.Threading.Timer(new System.Threading.TimerCallback(delegate(object state)
                {
                    ReDraw();
                    if (_resizeTimer == null) return;
                    _resizeTimer.Dispose();
                    _resizeTimer = null;
                }), null, _resizeDelay, System.Threading.Timeout.Infinite);
        }

        public void ReDraw()
        {
            this.Dispatcher.Invoke((Action)(() =>
                {
                    var dv = _children[0] as DrawingVisual;
                    DrawingContext drawingContext = dv.RenderOpen();
                    drawingContext.DrawText(this._formattedText, new Point(0, 0));
                    drawingContext.Close();
                }));
        }

        //===========================================================
        //Overrides

        protected override int VisualChildrenCount { get { return _children.Count; } }

        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= _children.Count)
                throw new ArgumentOutOfRangeException();

            return _children[index];
        }
    }
}

I have a barebones WPF app that has about a Meg of ASCII text to display. I initially put a TextBlock in a WrapPanel in a ScrollViewer. This correctly scrolled and resized when I resized the window, but it was super slow! I needed something faster.

So I put the text in FormattedText, and rendered that using a custom control. That was much faster, but it didn't resize. So I made my custom control resize. But it would ReDraw too many times a second, so I made it only redraw every 100ms.

Much better. Rendering and Resizing still isn't great but it's much better than it was. But I lost scrolling.

Eventually I need a solution that does a lot - but for now I'm trying to have a solution that does a little: show a mem of text, wrap, have a scrollbar, and be performant. Eventually, I'd like it to scale to a gig of text, have colors inline, some mouseover/click events for portions of the text...

How can I make FormattedText (or perhaps more accurately, a DrawingVisual) have a Vertical Scrollbar?

Here's my FrameworkElement that shows my FormattedText:

using System;
using System.Windows;
using System.Windows.Media;

namespace Recall
{
    public class LightweightTextBox : FrameworkElement
    {
        private VisualCollection _children;
        private FormattedText _formattedText;
        private System.Threading.Timer _resizeTimer;
        private const int _resizeDelay = 100;

        public double MaxTextWidth
        {
            get { return this._formattedText.MaxTextWidth; }
            set { this._formattedText.MaxTextWidth = value; }
        }

        public LightweightTextBox(FormattedText formattedText)
        {
            this._children = new VisualCollection(this);
            this._formattedText = formattedText;

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();
            drawingContext.DrawText(this._formattedText, new Point(0, 0));
            drawingContext.Close();
            _children.Add(drawingVisual);

            this.SizeChanged += new SizeChangedEventHandler(LightweightTextBox_SizeChanged);
        }

        void LightweightTextBox_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.MaxTextWidth = e.NewSize.Width;

            if (_resizeTimer != null)
                _resizeTimer.Change(_resizeDelay, System.Threading.Timeout.Infinite);
            else
                _resizeTimer = new System.Threading.Timer(new System.Threading.TimerCallback(delegate(object state)
                {
                    ReDraw();
                    if (_resizeTimer == null) return;
                    _resizeTimer.Dispose();
                    _resizeTimer = null;
                }), null, _resizeDelay, System.Threading.Timeout.Infinite);
        }

        public void ReDraw()
        {
            this.Dispatcher.Invoke((Action)(() =>
                {
                    var dv = _children[0] as DrawingVisual;
                    DrawingContext drawingContext = dv.RenderOpen();
                    drawingContext.DrawText(this._formattedText, new Point(0, 0));
                    drawingContext.Close();
                }));
        }

        //===========================================================
        //Overrides

        protected override int VisualChildrenCount { get { return _children.Count; } }

        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= _children.Count)
                throw new ArgumentOutOfRangeException();

            return _children[index];
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

生死何惧 2025-01-09 20:11:58

对于简单文本,只读 TextBox 非常好。对于更复杂的问题,您可以使用 FlowDocuments(可以托管在 FlowDocumentScrollViewer 中),TextBlocks 还托管 流动内容,但不适合大量内容。

MSDN

TextBlock没有针对需要显示多行内容的场景进行优化;对于这种情况,FlowDocument 与就性能而言,适当的查看控件是比 TextBlock 更好的选择。在 TextBlock 之后,FlowDocumentScrollViewer 是用于显示流内容的下一个最轻量级的控件,并且仅提供具有最小 UI 的滚动内容区域。 FlowDocumentPageViewer 围绕“page-at-”进行了优化a-time”流内容观看模式。最后,FlowDocumentReader 支持最丰富的设置功能查看流量内容,但相应的重量也较重。

For simple text a readonly TextBox is pretty good. For more complex matters you can use FlowDocuments (which can be hosted in a FlowDocumentScrollViewer), TextBlocks also host flow content but are not intended for larger amounts.

MSDN:

TextBlock is not optimized for scenarios that need to display more than a few lines of content; for such scenarios, a FlowDocument coupled with an appropriate viewing control is a better choice than TextBlock, in terms of performance. After TextBlock, FlowDocumentScrollViewer is the next lightest-weight control for displaying flow content, and simply provides a scrolling content area with minimal UI. FlowDocumentPageViewer is optimized around "page-at-a-time" viewing mode for flow content. Finally, FlowDocumentReader supports the richest set functionality for viewing flow content, but is correspondingly heavier-weight.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文