.net 具有多个文本框的慢速文本渲染

.net 具有多个文本框的慢速文本渲染,.net,wpf,winforms,performance,.net,Wpf,Winforms,Performance,我是一名Windows窗体开发人员,目前正在玩弄WPF。为了快速比较文本框中文本呈现的两种技术的性能,我编写了一个小程序,在窗口中创建大量文本框,并每100毫秒更新一次文本 令我惊讶的是,测试应用程序的WPF版本渲染速度比WinForms版本慢得多。大多数情况下,应用程序根本没有响应,例如,当我尝试调整窗口大小时。WinForms版本的应用程序运行平稳 所以我的问题是:我使用WPF控件的方式是否有问题(我在WPF中使用WrapPanel作为控件容器,在WinForms中使用FlowLayoutP

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

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

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

WPF:

使用系统;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Threading;
命名空间性能测试WPF
{
公共部分类主窗口:窗口
{
调度程序计时器=新调度程序();
随机_r=新随机();
公共主窗口()
{
初始化组件();
对于(int i=0;i<400;i++)
this.wrapPanel.Children.Add(新文本框{Height=23,Width=120,Text=“TextBox”});
_计时器间隔=新的时间间隔(0,0,0,100);
_timer.Tick+=\u timer\u Tick;
_timer.Start();
}
私有void\u timer\u Tick(对象发送方,事件参数e)
{
foreach(wrapPanel.Children中的变量child)
{
var textBox=作为textBox的子对象;
如果(文本框!=null)
{
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();
                }
            }
        }
    }
}
使用系统;
使用System.Windows.Forms;
命名空间PerformanceTestWinforms
{
公共部分类Form1:Form
{
定时器_Timer=新定时器();
随机_r=新随机();
公共表格1()
{
初始化组件();
对于(int i=0;i<400;i++)
this.flowLayoutPanel1.Controls.Add(新文本框{Height=23,Width=120,Text=“TextBox”});
_计时器。间隔=100;
_timer.Tick+=\u timer\u Tick;
_timer.Start();
}
私有void\u timer\u Tick(对象发送方,事件参数e)
{
foreach(flowLayoutPanel1.Controls中的变量子级)
{
var textBox=作为textBox的子对象;
如果(文本框!=null)
{
Text=_r.Next(0,1000).ToString();
}
}
}
}
}

我认为问题在于显式分派,请尝试以下基于绑定的示例:

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.Collections.Generic;
使用系统组件模型;
使用System.Linq;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
使用System.Windows.Threading;
命名空间WpfPerfTest
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
定时器(u定时器),;
随机_r=新随机();
私有只读列表_值=新列表();
公共主窗口()
{
初始化组件();
对于(int i=0;i<400;i++)
{
var值=新值ViewModel();
var tb=新文本框{Height=23,Width=120};
tb.SetBinding(TextBox.TextProperty,新绑定(“值”){Source=Value});
this.wrapPanel.Children.Add(tb);
此._值。添加(值);
}
_定时器=新定时器(o=>
{
foreach(此中的var值。\u值)
value.value=_r.Next(0,1000).ToString();
},空,0,100);
}
}
class ValueViewModel:InotifyProperty已更改,其中T:class
{
私有T_值=默认值(T);
公共价值
{
获取{返回_值;}
设置
{
如果(值!=\u值)
{
_价值=价值;
不动产变更(“价值”);
}
}
}
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged(字符串名称)
{
this.PropertyChanged?.Invoke(this,newpropertychangedeventargs(name));
}
}
}

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

不会在这里得出结论。也许是调度程序周期比较昂贵。无法在我的计算机上进行分析(需要更高的凭据);看看你是否可以这样做,找出哪些函数实际上是瓶颈。谢谢,这真的更好用。但是为什么这里的调度速度更快(我猜这里发生了某种隐式调度,因为计时器现在是异步执行回调的System.Threading.timer)?如果使用绑定,则调度隐式进行,因此可以更有效地调度,或者更新被合并到现有循环中。WPF dispatcher的内部结构相当复杂,建议提供详细信息。
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));
        }
    }
}