在WPF中显示大约一兆文本

在WPF中显示大约一兆文本,wpf,formatted-text,Wpf,Formatted Text,我有一个赤裸裸的WPF应用程序,可以显示大约一兆ASCII文本。我最初在ScrollViewer的WrapPanel中放了一个TextBlock。当我调整窗口大小时,它正确地滚动和调整了大小,但是它太慢了!我需要更快的东西 因此,我将文本放在FormattedText中,并使用自定义控件呈现它。这要快得多,但它没有调整大小。因此,我调整了自定义控件的大小。但它每秒会重画太多次,所以我只让它每100毫秒重画一次 好多了。渲染和调整大小仍然不是很好,但比以前好多了。但我失去了滚动 最终,我需要一个能

我有一个赤裸裸的WPF应用程序,可以显示大约一兆ASCII文本。我最初在ScrollViewer的WrapPanel中放了一个TextBlock。当我调整窗口大小时,它正确地滚动和调整了大小,但是它太慢了!我需要更快的东西

因此,我将文本放在FormattedText中,并使用自定义控件呈现它。这要快得多,但它没有调整大小。因此,我调整了自定义控件的大小。但它每秒会重画太多次,所以我只让它每100毫秒重画一次

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

最终,我需要一个能做很多事情的解决方案——但现在我正在尝试一个能做一点事情的解决方案:显示一段文字、换行、有一个滚动条,然后执行。最后,我希望它能够扩展到一格文本,内联颜色,为部分文本设置一些鼠标悬停/点击事件

如何使格式化文本(或者更准确地说,DrawingVisual)具有垂直滚动条

下面是显示格式化文本的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];
        }
    }
}
使用系统;
使用System.Windows;
使用System.Windows.Media;
名称空间调用
{
公共类LightweightTextBox:FrameworkElement
{
儿童私人视觉采集;
私有格式化文本_格式化文本;
专用System.Threading.Timer\u resizeTimer;
私有常量int_resizeDelay=100;
公共双MaxTextWidth
{
获取{返回此。\u formattedText.MaxTextWidth;}
设置{this.\u formattedText.MaxTextWidth=value;}
}
公共LightweightTextBox(格式化文本格式化文本)
{
this.\u children=新的视觉集合(this);
这是。_formattedText=formattedText;
DrawingVisual DrawingVisual=新建DrawingVisual();
DrawingContext DrawingContext=drawingVisual.RenderOpen();
drawingContext.DrawText(this._formattedText,新点(0,0));
drawingContext.Close();
_添加(drawingVisual);
this.SizeChanged+=新的SizeChangedEventHandler(LightweightTextBox\u SizeChanged);
}
void LightweightTextBox\u SizeChanged(对象发送方,SizeChangedEventArgs e)
{
this.MaxTextWidth=e.NewSize.Width;
如果(_resizeTimer!=null)
_resizeTimer.Change(_resizeDelay,System.Threading.Timeout.Infinite);
其他的
_resizeTimer=new System.Threading.Timer(new System.Threading.TimerCallback)(委托(对象状态)
{
重画();
if(_resizeTimer==null)返回;
_resizeTimer.Dispose();
_resizeTimer=null;
}),null,_resizeDelay,System.Threading.Timeout.Infinite);
}
公共无效重绘()
{
this.Dispatcher.Invoke((操作)(()=>
{
var dv=_子项[0]作为DrawingVisual;
DrawingContext DrawingContext=dv.renderropen();
drawingContext.DrawText(this._formattedText,新点(0,0));
drawingContext.Close();
}));
}
//===========================================================
//覆盖
受保护的重写int VisualChildrenCount{get{return}\u children.Count;}
受保护的重写Visual GetVisualChild(int索引)
{
如果(索引<0 | |索引>=_children.Count)
抛出新ArgumentOutOfRangeException();
返回子项[索引];
}
}
}

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

:

TextBlock未针对需要显示多行内容的场景进行优化;对于此类场景,就性能而言,与TextBlock相比,结合适当的查看控件是更好的选择。在TextBlock之后,是用于显示流内容的下一个最轻的控件,它只提供了一个具有最小UI的滚动内容区域。围绕流内容的“一次一页”查看模式进行优化。最后,它支持查看流内容的最丰富的功能集,但相应的重量更重


报告还指出,FlowDocuments是资源最密集的文档,更重要的是TextBlock。当然我没有试过,但是如果它应该比TextBlock慢,而且太慢了…@Tomriter:如果没有进行虚拟化,那很可能是,我不知道。当然,流文档在某些方面更重,但这并不意味着显示性能也更差。此外,当你打算以后做更复杂的事情时,你可能最终会使你的控制权变得像已经存在的东西一样沉重,从而提供你所需要的一切。