使用定时器在C#更新UI使用定时器在C#更新UI(Updating UI in C# using T

2019-05-12 11:34发布

我的工作让我的应用程序,从串口读取数据并更新在UI上更有效的计量,我想问在我的代码的一些意见,处理用户界面的变化。 我有一个定时器设置检查数据被发送到COM端口和更新从COM端口接收到的变量的UI另一个计时器。 基本上所发生的事情是我在旋转仪。 这是我用于处理图形代码...

void timer_Tick(object sender, EventArgs e) //Timer regulates how often the gauge is     updated on the UI
{
    if (pictureBox1.Image != null)
        pictureBox1.Image.Dispose(); // dispose old image (you might consider reusing it rather than making a new one each frame)

    Point test = new Point((int)_xCor, (int)_yCor);
    Image img = new Bitmap(400, 400); // The box tht contains the image <--- Play around with this more
    pictureBox1.Image = img; // Setting the img Image to the pictureBox class?


    Graphics g = Graphics.FromImage(pictureBox1.Image); // G represents a drawing surface
    Matrix mm1 = new Matrix();
    //
    mm1.RotateAt((float)(90 + (((12.5 * state) - 20.95) * 6)), new Point((int)_xrotate, (int)_yrotate), MatrixOrder.Append);
    GraphicsPath gp = new GraphicsPath();
    g.Transform = mm1; // transform the graphics object so the image is rotated
    g.DrawImage(imgpic, test); // if the image needs to be behind the path, draw it beforehand
    mm1.Dispose();// prevent possible memory leaks
    gp.Dispose();// prevent possible memory leaks
    g.Dispose(); // prevent possible memory leaks
    pictureBox1.Refresh();
}

我想知道,如果有,我可以在屏幕上旋转图像更有效的方式。 我觉得必须有,但我无法弄清楚。

Answer 1:

这是我第二次为一个WinForms问题WPF的解决方案。

只需复制并粘贴到文件我的代码 - >新项目 - > WPF应用程序,看看效果如何。

也看看这个代码是多么的简单(我使用的是随机值,这样你就可以删除,并根据需要进行修改)。

我用该图(的<Path/>在XAML一部分)不足以一个压力表。 我只是有这样的路径已经得出和我懒得来创建一个新的。 您应该创建一个新的绘图(我推荐使用Expression Blend中)。 但是你可以看到正在应用的旋转和速度有多快它的工作原理。

using System;
using System.Threading;
using System.Windows;
using System.ComponentModel;

namespace WpfApplication4
{
    public partial class Window2
    {
        public Window2()
        {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    }

    public class ViewModel: INotifyPropertyChanged
    {
        private double _value;
        public double Value
        {
            get { return _value; }
            set
            {
                _value = value;
                NotifyPropertyChange("Value");
            }
        }

        private int _speed = 100;
        public int Speed
        {
            get { return _speed; }
            set
            {
                _speed = value;
                NotifyPropertyChange("Speed");
                Timer.Change(0, value);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChange(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        private System.Threading.Timer Timer;

        public ViewModel()
        {
            Rnd = new Random();
            Timer = new Timer(x => Timer_Tick(), null, 0, Speed);
        }

        private void Timer_Tick()
        {
            Application.Current.Dispatcher.BeginInvoke((Action) (NewValue));
        }

        private Random Rnd;
        private void NewValue()
        {
            Value = Value + (Rnd.Next(20) - 10);
        }
    }
}

XAML:

<Window x:Class="WpfApplication4.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window2" WindowState="Maximized">
    <DockPanel>
        <StackPanel DockPanel.Dock="Top">
            <TextBlock Text="Delay (MS):" Margin="2"/>
            <Slider Width="200" Minimum="100" SmallChange="1" LargeChange="10" Maximum="1500" Value="{Binding Speed}" Margin="2"/>
            <TextBlock Text="Current Value:" Margin="2"/>
            <TextBox Text="{Binding Value}" Margin="2"/>
        </StackPanel>

        <Path Data="M0.95991516,0.5 L73.257382,1.866724 90.763535,1.866724 90.763535,90.822725 66.430534,90.822725 66.430534,26.075016 0.5,24.828653 z" Fill="#FF506077" RenderTransformOrigin="0.861209625003783,0.507482926584064" Stretch="Fill" Stroke="Black">
            <Path.LayoutTransform>
                <TransformGroup>
                    <ScaleTransform ScaleY="1" ScaleX="-1"/>
                    <SkewTransform AngleY="0" AngleX="0"/>
                    <RotateTransform Angle="{Binding Value}" x:Name="Rotation"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Path.LayoutTransform>
        </Path>
    </DockPanel>
</Window>


Answer 2:

这是很难回答你的问题,因为你的要求图像的“更高效”自转是相当模糊的。 我不知道,如果通过更有效的你的意思是:

  • 更好的性能;
  • 更少的存储器使用量;
  • 或者干脆少,或更优雅,代码

在任何情况下,除非你是在谈论使代码更“优雅”比我能想出的唯一的事情是,你可以,而且也应该,重复使用相同的图像/位图。 而不是创建一个新的每一个你可以只清除您使用的是一个和时间重新绘制图像。

您可能还需要检查你的计时器的刷新速率,用于更新UI。 约24帧速率 - 每秒30帧应该是足够了。 任何更多的是在这种情况下矫枉过正,它将大多只是浪费CPU周期。

你也应该启用双缓冲防止闪烁。

编辑

根据您的意见,这听起来像的问题不是性能,但COM端口定时器的时间间隔和UI计时器之间的差异。 这听起来是更新用户界面不会跑得不够快,检测的改变定时器..你有什么区间?



Answer 3:

看起来你在Windows窗体中这样做呢? 使用:

Graphics.RotateTransform

如果我可以谦卑地建议,不过,如果你试图做任何事情,甚至远程有趣图形,它可能是值得的投资加紧WPF。 Windows窗体依赖于旧的API GDI不属于硬件加速(不像是建立在DirectX WPF),使其成为任何类型的图形严重的不良平台。 不管你如何“高效”与WinForms的获得,你将永远无法与同时通过硬件加速支持的任何竞争。



Answer 4:

旋转使用GDI +将是缓慢的,周期的位图。 最大的性能提升,你可能会提出的是,停止使用位图用于此目的,只是定制与GDI +矢量图形绘制你的仪表。 你仍然可以使用位图背景和使用矢量图形的绘制计量的针,如果适用。 这将是数量级比旋转位图快。

接下来的事情我想看看它是否是结合使用图片框与动态位图(即不断变化)是真的走正道; 图片框可能会在自己的位图每一个它的更新时间,这是真的只是浪费周期做额外的处理。 为什么不直接绘制位图到屏幕上的自己吗? 此外,请确保您的位图与最佳绘制性能(PArgb32bpp)正确的像素格式创建。

最后,除非你输入的数据是变化值络绎不绝,我会考虑完全抛弃定时器,只是使用的BeginInvoke信号您的UI线程时,它的时间重绘屏幕。 您当前的解决方案可能免受不必要的等待时间是患之间的计时器滴答声,它也可能往往需要重绘计。



文章来源: Updating UI in C# using Timer