【问题标题】:Slow text rendering with many text boxes带有许多文本框的慢文本渲染
【发布时间】:2016-05-30 13:18:49
【问题描述】:

我是一名 Windows 窗体开发人员,目前正在玩弄 WPF。为了快速比较两种技术在文本框中呈现文本的性能,我编写了一个小程序,它在一个窗口中创建大量文本框,并每 100 毫秒更新一次它们的文本。

令我惊讶的是,测试应用程序的 WPF 版本的渲染速度比 WinForms 版本慢得多。大多数时候应用程序根本没有响应,例如当我尝试调整窗口大小时。 WinForms版应用运行流畅。

所以我的问题是:我使用 WPF 控件的方式是否有问题(我在 WPF 中使用 WrapPanel 作为控件容器,在 WinForms 中使用 FlowLayoutPanel)?还是文本渲染真的比 WinForms 慢?

WPF:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace PerformanceTestWPF
{
    public partial class MainWindow : Window
    {
        DispatcherTimer _timer = new DispatcherTimer();
        Random _r = new Random();

        public MainWindow()
        {
            InitializeComponent();

            for (int i = 0; i < 400; i++)
                this.wrapPanel.Children.Add(new TextBox {Height = 23, Width = 120, Text = "TextBox"});

            _timer.Interval = new TimeSpan(0,0,0,0, 100);
            _timer.Tick += _timer_Tick;
            _timer.Start();

        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            foreach (var child in wrapPanel.Children)
            {
                var textBox = child as TextBox;
                if (textBox != null)
                {
                    textBox.Text = _r.Next(0, 1000).ToString();
                }
            }
        }
    }
}

WinForms:

using System;
using System.Windows.Forms;

namespace PerformanceTestWinforms
{
    public partial class Form1 : Form
    {
        Timer _timer = new Timer();
        Random _r = new Random();

        public Form1()
        {
            InitializeComponent();

            for (int i = 0; i < 400; i++)
                this.flowLayoutPanel1.Controls.Add(new TextBox { Height = 23, Width = 120, Text = "TextBox" });

            _timer.Interval = 100;
            _timer.Tick += _timer_Tick;
            _timer.Start();
        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            foreach (var child in flowLayoutPanel1.Controls)
            {
                var textBox = child as TextBox;
                if (textBox != null)
                {
                    textBox.Text = _r.Next(0, 1000).ToString();
                }
            }
        }
    }
}

【问题讨论】:

  • 这里不会贸然下结论。也许这是昂贵的调度程序周期。无法在我的机器上进行分析(需要更高的凭据);看看您是否可以这样做以找出哪些功能实际上是瓶颈。

标签: .net wpf winforms performance


【解决方案1】:

我认为问题在于显式调度,试试这个基于绑定的示例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace WpfPerfTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Timer _timer;
        Random _r = new Random();

        private readonly List<ValueViewModel<string>> _values = new List<ValueViewModel<string>>();

        public MainWindow()
        {
            InitializeComponent();

            for (int i = 0; i < 400; i++)
            {
                var value = new ValueViewModel<string>();
                var tb = new TextBox { Height = 23, Width = 120 };
                tb.SetBinding(TextBox.TextProperty, new Binding("Value") { Source = value });
                this.wrapPanel.Children.Add(tb);
                this._values.Add(value);
            }

            _timer = new Timer(o =>
            {
                foreach (var value in this._values)
                    value.Value = _r.Next(0, 1000).ToString();
            }, null, 0, 100);
        }
    }

    class ValueViewModel<T> : INotifyPropertyChanged where T : class
    {

        private T _Value = default(T);
        public T Value
        {
            get { return _Value; }
            set
            {
                if (value != _Value)
                {
                    _Value = value;
                    OnPropertyChanged("Value");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;


        protected virtual void OnPropertyChanged(string name)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

在调整大小的过程中,它仍然有些卡顿,但除此之外它的性能要好得多。

【讨论】:

  • 谢谢,这确实更好。但是为什么这里调度更快(我猜这里发生了某种隐式调度,因为计时器现在是一个异步执行回调的 System.Threading.Timer)?
  • 如果您使用绑定,则调度会隐式发生,因此可能会更有效地调度或将更新合并到现有循环中。 WPF 调度程序内部相当复杂,建议this article 了解详细信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 2014-09-15
  • 2014-11-17
  • 1970-01-01
  • 2011-06-26
相关资源
最近更新 更多