使用计时器更新 C# 中的 UI [英] Updating UI in C# using Timer

查看:35
本文介绍了使用计时器更新 C# 中的 UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力使我的应用程序能够更高效地从串行端口读取数据并更新 UI 上的仪表,我想就处理 UI 更改的代码寻求一些建议.我设置了一个计时器来检查发送到 COM 端口的数据,另一个计时器使用从 COM 端口接收到的变量更新 UI.基本上发生的事情是我正在旋转仪表.这是我处理图形的代码...

I am working on making my application that reads data from the serial port and updates a gauge on the UI more efficient and I wanted to ask for some advice on my code that processes the UI changes. I have a timer set to check for data being sent to the COM port and another timer that updates the UI with the variable received from the COM port. Basically what is happening is I am rotating a gauge. Here is my code for handling the graphics...

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();
}

我想知道是否有更有效的方法可以在屏幕上旋转图像.我觉得必须有,但我想不通.

I am wondering if there is a more efficient way that I can rotate the Image on screen. i feel like there has to be but I can't figure it out.

推荐答案

这是我第二次为 winforms 问题提供 WPF 解决方案.

This is the second time I provide a WPF solution for a winforms problem.

只需将我的代码复制并粘贴到文件中 -> 新项目 -> WPF 应用程序,然后自己查看结果.

Just copy and paste my code in a file -> new project -> WPF Application and see the results for yourself.

还要看看这段代码到底有多简单(我使用的是随机值,因此您可以将其删除并根据您的需要进行调整).

Also take a look at how simple this code really is (I'm using random values, so you can remove that and adapt it to your needs).

我使用的绘图(XAML 中的 部分)对于仪表来说是不够的.我刚刚已经绘制了该路径,我懒得创建一个新路径.您应该创建一个新绘图(我建议使用 Expression Blend).但是您可以看到正在应用的旋转以及它的运行速度.

The drawing I used (the <Path/> part in XAML) is not adequate for a Gauge. I just had that Path already drawn and I'm too lazy to create a new one. You should create a new drawing (I recommend using Expression Blend). But you can see the Rotation being applied and how fast it works.

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>

这篇关于使用计时器更新 C# 中的 UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆