【问题标题】:Displaying about a Meg of Text in WPF在 WPF 中显示大约一兆的文本
【发布时间】:2012-02-06 21:19:33
【问题描述】:

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

所以我将文本放在 FormattedText 中,并使用自定义控件进行渲染。这要快得多,但它没有调整大小。所以我让我的自定义控件调整大小。但它每秒会重绘太多次,所以我让它每 100 毫秒重绘一次。

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

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

如何使 FormattedText(或者更准确地说,一个 DrawingVisual)有一个垂直滚动条?

这是显示我的 FormattedText 的 FrameworkElement:

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];
        }
    }
}

【问题讨论】:

    标签: wpf formatted-text


    【解决方案1】:

    对于简单的文本,只读的TextBox 非常好。对于更复杂的问题,您可以使用FlowDocuments(可以在FlowDocumentScrollViewer 中托管),TextBlocks 也可以在flow content 上托管,但不适用于较大的金额。

    MSDN:

    TextBlock 没有针对需要显示多于几行内容的场景进行优化;对于这种情况,就性能而言,FlowDocument 加上适当的查看控件是比 TextBlock 更好的选择。在 TextBlock 之后,FlowDocumentScrollViewer 是用于显示流内容的下一个最轻量级的控件,它只是提供了一个带有最少 UI 的滚动内容区域。 FlowDocumentPageViewer 针对流内容的“一次一页”查看模式进行了优化。最后,FlowDocumentReader 支持查看流内容的最丰富的集合功能,但相应地更重。

    【讨论】:

    • Optimizing WPF Performance article 还说 FlowDocuments 是最耗费资源的,更何况是 TextBlock。当然我没有尝试过,但如果它应该比 TextBlock 慢,那就太慢了......
    • @TomRitter:如果没有进行虚拟化,那很可能,但我不知道。当然 FlowDocument 在某些方面更重,但这并不意味着显示性能也更差。此外,当您打算稍后做更复杂的事情时,您最终可能会使您的控制权与现有的控制权一样重,以提供您需要的一切。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    相关资源
    最近更新 更多