将变量传递给类中的计时器事件

本文关键字:计时器 事件 变量 | 更新日期: 2023-09-27 18:16:37

我在一个类中有一个方法,它从/到Form1接收并返回多个参数。我需要使用一个定时事件来使用这些参数执行一些代码。我已经安排了这个简化的代码来显示动态的:

class Motor
{
    public static System.Timers.Timer _timer;
    int valReg = 30;
    public void PID(decimal _actualSpeed, Decimal _speedRequest, out Decimal _pwmAuto, out decimal _preValReg)
    {
        _timer = new System.Timers.Timer();
        _timer.Interval = (3000);
        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timerAutoset);
        _timer.Enabled = true;
        // {....}
        _pwmAuto = valReg;
        _preValReg = valReg - 1;
    }
    static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e)
    {
        /* here I need to work with:
         _actualSpeed
         _speedRequest
         _pwmAuto
         _preValReg
        and send back the last two variables
         */
    }    
}

这是我如何从Form1按钮传递和接收变量:

        private void button4_Click(object sender, EventArgs e)
        {
        // some code ................
        Motor mtr = new Motor();
        mtr.PID(speedRequest, actualSpeed, out pwmAuto, out xxx);
        //..more code

我如何通过/从_timerAutoset事件获得这些参数?

将变量传递给类中的计时器事件

我倾向于使用匿名委托来解决这个问题。

public void PID(decimal _actualSpeed, Decimal _speedRequest, out Decimal _pwmAuto, out decimal _preValReg)
{
    _pwmAuto = valReg;
    _preValReg = valReg - 1;
     // Because we cannot use [out] variables inside the anonymous degegates,
     // we make a value copy
     Decimal pwmAutoLocal = _pwmAuto;
     Decimal preValRegLocal = _preValReg;
    _timer = new System.Timers.Timer();
    _timer.Interval = (3000);
    _timer.Elapsed += (sender, e) => { HandleTimerElapsed(_actualSpeed, _speedRequst, pwmAutoLocal, preValRegLocal); };        
    _timer.Enabled = true;
    // {....}
}
static void HandleTimerElapsed(Decimal actualSpeed, Decimal speedRequst, Decimal pwmAuto, Decimal preValReg)
{
   // (...)
}
当委托从封闭块访问局部变量时,您必须注意。仔细检查代码,以确保存储在这些变量中的值不会在事件处理程序的赋值和该处理程序的调用之间发生变化。

这些参数似乎来自其他地方。一种方法是通过delegate传递callback,并使用它从。

获取更新的值。

另一种方法是创建一个class并将其传递给Motor的构造函数,并使用其在_timerAutoset中的引用来获得更新的值。

使用代表

:

class Motor
{
    public static System.Timers.Timer _timer;
    int valReg = 30;
    public delegate TimerParam ParameterizedTimerDelegate();
    public static ParameterizedTimerDelegate TimerCallback { get; set; }
    public void PID()
    {
        _timer = new System.Timers.Timer();
        _timer.Interval = (3000);
        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timerAutoset);
        _timer.Enabled = true;
        // {....}
        //Param.PwmAuto = valReg;
        //Param.PreValReg = valReg - 1;
    }
    static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e)
    {
        TimerParam param = TimerCallback();
        /* here you can use:
         Param.ActualSpeed
         Param.SpeedRequest
         Param.PwmAuto
         Param.PreValReg
        */
    }
}

使用共享实例:

class TimerParam
{
    public decimal ActualSpeed { get; set; }
    public decimal SpeedRequest { get; set; }
    public Decimal PwmAuto { get; set; }
    public decimal PreValReg { get; set; }
}
class Motor
{
    public static System.Timers.Timer _timer;
    int valReg = 30;
    public TimerParam Param { get; set; }
    public void PID(TimerParam param)
    {
        Param = param;
        _timer = new System.Timers.Timer();
        _timer.Interval = (3000);
        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timerAutoset);
        _timer.Enabled = true;
        // {....}
        Param.PwmAuto = valReg;
        Param.PreValReg = valReg - 1;
    }
    static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e)
    {
        /* here you can use:
         Param.ActualSpeed
         Param.SpeedRequest
         Param.PwmAuto
         Param.PreValReg
        */
    }
}

然后,您可以更新传递给Motor类的TimerParam实例,计时器将始终获得更新的值。

您可以尝试使用lambda表达式插入额外的参数

  _timer.Elapsed += (sender, e) => _timerAutoset(sender, e, _actualSpeed,_speedRequest);

你的方法就像

static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e,decimal speed,decimal speedRequest)

我使用一个Backgroundworker风格的类,名为"ScheduledWorker",它在单独的线程上执行循环操作,并在每次执行此后台操作后返回主线程。

对于数据交换对象变量可以在启动ScheduledWorker时传递给后台操作,也可以在ScheduledWorker运行时更改。在后台过程中,这个对象可以通过DoScheduledWorkEventArgs.Argument调用。DoWork事件被引发的时间可以通过DoScheduledWorkEventArgs来调用。SignalTime 属性。ScheduledWorker 向主线程报告后台操作的结果和进度的方式与BackgroundWorker类相同。

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
namespace ScheduledWorker
{
    /// <summary>
    /// Executes a recurring operation on a separate thread.
    /// </summary>
    [DefaultEvent("DoWork")]
    [HostProtection(SharedState = true)]
    public partial class ScheduledWorker : Component, ISupportInitialize
    {
        private bool enabled;
        private bool delayedEnable;
        private bool initializing;
        private bool disposed;
        private readonly ManualResetEvent doNotDisposeWaitHandle = new ManualResetEvent(false);
        private int disposeWaitMSec;
        private bool cancellationPending;
        private bool isRunning;
        private bool isOccupied;
        private bool isWorking;
        private object argument;
        private readonly object statusChangeLockObject = new object();
        private readonly object doWorkKey = new object();
        private readonly object runWorkerCompletedKey = new object();
        private readonly object progressChangedKey = new object();
        private readonly EventHandler<DoScheduledWorkEventArgs> workHandler;
        private readonly SendOrPostCallback completedCallback;
        private readonly SendOrPostCallback progressCallback;
        private AsyncOperation mainThreadOperation;
        private Timer timer;
        private double interval;
        /// <summary>
        /// Initializes a new instance of the ScheduledWorker class and sets the <see cref="ScheduledWorker.Interval"/> property to 100 milliseconds.
        /// </summary>
        public ScheduledWorker() : this(100, -1) { }
        /// <summary>
        /// Initializes a new instance of the ScheduledWorker class, and sets the <see cref="ScheduledWorker.Interval"/> property to the specified number of milliseconds.
        /// </summary>
        /// <param name="interval">The time, in milliseconds, between events. The value must be greater than zero and less than or equal to <see cref="int.MaxValue"/>."/></param>
        public ScheduledWorker(double interval, int disposeWaitMSec) : base()
        {
            this.interval = interval;
            this.disposeWaitMSec = disposeWaitMSec;
            completedCallback = new SendOrPostCallback(AsynOperationCompleted);
            progressCallback = new SendOrPostCallback(ProgressReporter);
            initializing = false;
            delayedEnable = false;
            workHandler = new EventHandler<DoScheduledWorkEventArgs>(WorkerThreadStart);
        }
        /// <summary>
        /// Occurs when <see cref="ScheduledWorker.RunWorkerAsync"/> or <see cref="ScheduledWorker.RunWorkerAsync(object)"/> are called.
        /// </summary>
        public event EventHandler<DoScheduledWorkEventArgs> DoWork
        {
            add
            {
                Events.AddHandler(doWorkKey, value);
            }
            remove
            {
                Events.RemoveHandler(doWorkKey, value);
            }
        }
        /// <summary>
        /// Occurs when the background operation has completed, has been canceled, or has raised an exception.
        /// </summary>
        public event EventHandler<RunWorkerCompletedEventArgs> RunWorkerCompleted
        {
            add
            {
                Events.AddHandler(runWorkerCompletedKey, value);
            }
            remove
            {
                Events.RemoveHandler(runWorkerCompletedKey, value);
            }
        }
        /// <summary>
        /// Occurs when <see cref="ScheduledWorker.ReportProgress(int)"/> or <see cref="ScheduledWorker.ReportProgress(int, object)"/> are called.
        /// </summary>
        public event EventHandler<ProgressChangedEventArgs> ProgressChanged
        {
            add
            {
                Events.AddHandler(progressChangedKey, value);
            }
            remove
            {
                Events.RemoveHandler(progressChangedKey, value);
            }
        }
        /// <summary>
        /// Starts raising the <see cref="ScheduledWorker.DoWork"/> event by setting Enabled to true.
        /// </summary>
        public void RunWorkerAsync()
        {
            RunWorkerAsync(null);
        }
        /// <summary>
        /// Starts raising the <see cref="ScheduledWorker.DoWork"/> event by setting Enabled to true.
        /// </summary>
        /// <param name="argument">A parameter for use by the background operation to be executed in the <see cref="ScheduledWorker.DoWork"/> event handler.</param>
        public void RunWorkerAsync(object argument)
        {
            Argument = argument;
            Enabled = true;
        }
        /// <summary>
        /// Stops raising the <see cref="ScheduledWorker.DoWork"/> event by setting Enabled to false.
        /// </summary>
        public void Stop()
        {
            Enabled = false;
        }
        /// <summary>
        /// Gets or sets a value indicating whether the <see cref="ScheduledWorker.DoWork"/> event should be raised.
        /// </summary>
        [Category("Behavior")]
        public bool Enabled
        {
            get
            {
                lock (statusChangeLockObject)
                {
                    return enabled;
                }
            }
            set
            {
                if (DesignMode)
                {
                    delayedEnable = value;
                    enabled = value;
                }
                else if (initializing)
                {
                    delayedEnable = value;
                }
                else if (enabled != value)
                {
                    lock (statusChangeLockObject)
                    {
                        if (!value)
                        {
                            if (timer != null)
                            {
                                timer.Dispose();
                                timer = null;
                            }
                            enabled = false;
                            if (!isWorking)
                            {
                                if (!isOccupied)
                                {
                                    isRunning = false;
                                }
                                SetMainThreadOperationCompleted();
                            }
                        }
                        else
                        {
                            enabled = true;
                            if (timer == null && !isRunning)
                            {
                                if (disposed)
                                {
                                    throw new ObjectDisposedException(GetType().Name);
                                }
                                else
                                {
                                    int roundedInterval = Convert.ToInt32(Math.Ceiling(interval));
                                    isRunning = true;
                                    isOccupied = false;
                                    isWorking = false;
                                    cancellationPending = false;
                                    SetMainThreadOperationCompleted();
                                    mainThreadOperation = AsyncOperationManager.CreateOperation(null);
                                    timer = new Timer(MyTimerCallback, null, roundedInterval, roundedInterval);
                                }
                            }
                            else if (isRunning)
                            {
                                throw new InvalidOperationException("ScheduledWorker is busy.");
                            }
                            else
                            {
                                UpdateTimer();
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Gets or sets the interval, expressed in milliseconds, at which to raise the <see cref="ScheduledWorker.DoWork"/> event.
        /// It can be changed while the ScheduledWorker is running.
        /// </summary>
        [Category("Behavior"), DefaultValue(100d), SettingsBindable(true)]
        public double Interval
        {
            get
            {
                return interval;
            }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentException("Minimum interval is 1.");
                }
                else
                {
                    interval = value;
                    if (timer != null)
                    {
                        UpdateTimer();
                    }
                }
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether the ScheuledWorker can report progress updates.
        /// </summary>
        [DefaultValue(false)]
        public bool WorkerReportsProgress { get; set; }
        /// <summary>
        /// Raises the ProgressChanged event.
        /// </summary>
        /// <param name="percentProgress">The percentage, from 0 to 100, of the background operation that is complete.</param>
        public void ReportProgress(int percentProgress)
        {
            ReportProgress(percentProgress, null);
        }
        /// <summary>
        /// Raises the ProgressChanged event.
        /// </summary>
        /// <param name="percentProgress">The percentage, from 0 to 100, of the background operation that is complete.</param>
        /// <param name="userState">The state object passed to <see cref="ScheduledWorker.RunWorkerAsync(object)"/>.</param>
        public void ReportProgress(int percentProgress, object userState)
        {
            if (!WorkerReportsProgress)
            {
                throw new InvalidOperationException("This ScheduledWorker does not support reporting progress.");
            }
            else
            {
                mainThreadOperation.Post(progressCallback, new ProgressChangedEventArgs(percentProgress, userState));
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether the ScheduledWorker supports asynchronous cancellation.
        /// </summary>
        [DefaultValue(false)]
        public bool WorkerSupportsCancellation { get; set; }
        /// <summary>
        /// Gets a value indicating whether the application has requested cancellation of a background operation.
        /// </summary>
        [Browsable(false)]
        public bool CancellationPending
        {
            get
            {
                lock (statusChangeLockObject)
                {
                    return cancellationPending;
                }
            }
        }
        /// <summary>
        /// Requests cancellation of a pending background operation.
        /// </summary>
        public void CancelAsync()
        {
            if (!WorkerSupportsCancellation)
            {
                throw new InvalidOperationException("This ScheduledWorker does not support cancellation.");
            }
            else
            {
                lock (statusChangeLockObject)
                {
                    cancellationPending = true;
                    Stop();
                }
            }
        }
        /// <summary>
        /// Gets a value indicating whether the ScheduledWorker is running an asynchronous operation. This is the case until the SchedeuledWorker has been stopped (<see cref="ScheduledWorker.Enabled"/> = false) 
        /// and the last <see cref="ScheduledWorker.DoWork"/> event has completed.
        /// </summary>
        [Browsable(false)]
        public bool IsBusy
        {
            get
            {
                lock (statusChangeLockObject)
                {
                    return isRunning;
                }
            }
        }
        /// <summary>
        /// A parameter for use by the background operation to be executed in the <see cref="ScheduledWorker.DoWork"/> event handler.
        /// It can be changed while the ScheduledWorker is running.
        /// </summary>
        [Browsable(false)]
        public object Argument
        {
            get
            {
                return Interlocked.Exchange(ref argument, argument);
            }
            set
            {
                Interlocked.Exchange(ref argument, value);
            }
        }
        /// <summary>
        /// Begins the run-time initialization of a ScheduledWorker that is used on a form or by another component.
        /// </summary>
        public void BeginInit()
        {
            Close();
            initializing = true;
        }
        /// <summary>
        /// Ends the run-time initialization of a ScheduledWorker that is used on a form or by another component.
        /// </summary>
        public void EndInit()
        {
            initializing = false;
            enabled = delayedEnable;
        }
        private void MyTimerCallback(object state)
        {
            lock (statusChangeLockObject)
            {
                try
                {
                    if (enabled && !isOccupied)
                    {
                        doNotDisposeWaitHandle.Reset();
                        isOccupied = true;
                        isWorking = true;
                        FILE_TIME fileTime = new FILE_TIME();
                        SafeNativeMethods.GetSystemTimeAsFileTime(ref fileTime);
                        workHandler.BeginInvoke(this, 
                                                new DoScheduledWorkEventArgs(Argument,
                                                                             DateTime.FromFileTime((long)((((ulong)fileTime.ftTimeHigh) << 32) | (((ulong)fileTime.ftTimeLow) & 0xffffffff)))), 
                                                null, 
                                                null);
                    }
                }
                catch { }
            }
        }
        private void WorkerThreadStart(object sender, DoScheduledWorkEventArgs args)
        {
            Exception Error = null;
            try
            {
                if (CancellationPending)
                {
                    args.Cancel = true;
                }
                else
                {
                    OnDoWork(args);
                }
                if (args.Cancel)
                {
                    args.Result = null;
                    cancellationPending = true;
                }
            }
            catch (Exception ex)
            {
                Error = ex;
                args.Result = null;
            }
            finally
            {
                mainThreadOperation.Post(completedCallback, new RunWorkerCompletedEventArgs(args.Result, Error, args.Cancel));
                doNotDisposeWaitHandle.Set();
            }
        }
        protected void OnDoWork(DoScheduledWorkEventArgs args)
        {
            ((EventHandler<DoScheduledWorkEventArgs>)Events[doWorkKey])?.Invoke(this, args);
        }
        private void AsynOperationCompleted(object args)
        {
            lock (statusChangeLockObject)
            {
                isWorking = false;
                if (!enabled)
                {
                    isRunning = false;
                    SetMainThreadOperationCompleted();
                }
            }
            OnRunWorkerCompleted((RunWorkerCompletedEventArgs)args);
            lock (statusChangeLockObject)
            {
                isOccupied = false;
                if (!enabled)
                {
                    isRunning = false;
                    SetMainThreadOperationCompleted();
                }
            }
        }
        protected void OnRunWorkerCompleted(RunWorkerCompletedEventArgs args)
        {
            ((EventHandler<RunWorkerCompletedEventArgs>)Events[runWorkerCompletedKey])?.Invoke(this, args);
        }
        private void SetMainThreadOperationCompleted()
        {
            if (mainThreadOperation != null)
            {
                mainThreadOperation.OperationCompleted();
                mainThreadOperation = null;
            }
        }
        private void ProgressReporter(object arg)
        {
            OnProgressChanged((ProgressChangedEventArgs)arg);
        }
        protected void OnProgressChanged(ProgressChangedEventArgs args)
        {
            ((EventHandler<ProgressChangedEventArgs>)Events[progressChangedKey])?.Invoke(this, args);
        }
        private void UpdateTimer()
        {
            int roundedInterval = Convert.ToInt32(Math.Ceiling(interval));
            timer.Change(roundedInterval, roundedInterval);
        }
        protected override void Dispose(bool disposing)
        {
            disposed = true;
            Close();
            base.Dispose(disposing);
        }
        public void Close()
        {
            if (timer != null)
            {
                timer.Change(Timeout.Infinite, Timeout.Infinite);
                using (ManualResetEvent disposeWaitHandle = new ManualResetEvent(false))
                {
                    if (timer.Dispose(disposeWaitHandle))
                    {
                        disposeWaitHandle.WaitOne(disposeWaitMSec, false);
                    }
                    timer = null;
                }
            }
            initializing = false;
            delayedEnable = false;
            enabled = false;
            doNotDisposeWaitHandle.WaitOne(disposeWaitMSec, false);
            doNotDisposeWaitHandle.Close();
            SetMainThreadOperationCompleted();
        }
        [StructLayout(LayoutKind.Sequential)]
        internal struct FILE_TIME
        {
            internal int ftTimeLow;
            internal int ftTimeHigh;
        }
        private sealed class SafeNativeMethods
        {
            [ResourceExposure(ResourceScope.None)]
            [DllImport("Kernel32"), SuppressUnmanagedCodeSecurityAttribute()]
            internal static extern void GetSystemTimeAsFileTime(ref FILE_TIME lpSystemTimeAsFileTime);
        }
    }
    /// <summary>
    /// Provides data for the <see cref="ScheduledWorker.DoWork"/> event.
    /// </summary>
    public sealed class DoScheduledWorkEventArgs : DoWorkEventArgs
    {
        internal DoScheduledWorkEventArgs(object arg, DateTime signalTime) : base(arg)
        {
            SignalTime = signalTime;
        }
        /// <summary>
        /// Gets the date/time when the <see cref="ScheduledWorker.DoWork"/> event was raised.
        /// </summary>
        public DateTime SignalTime { get; }
    }
}

你可以在你的类中初始化它们,这样所有的方法都可以访问它们

 private void StartTimerForDeleteMessage(UC_ChatReceiveMessageControl ucChatReceiveMessageControl)
    {
        try
        {
            System.Timers.Timer aTimer = new System.Timers.Timer();
            aTimer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, ucChatReceiveMessageControl);
            aTimer.Interval = 1000;
            aTimer.Enabled = true;
        }
        catch (Exception ex)
        {
            Helper.WriteToLogFile("SetMessageBodyContentAfterAcknoledged ex::" + ex.Message, LoggingLevel.Errors);
        }
    }
    static void MyElapsedMethod(object sender, ElapsedEventArgs e, UC_ChatReceiveMessageControl ucChatReceiveMessageControl)
    {
        try
        {
        }
        catch (Exception ex)
        {
            Helper.WriteToLogFile("SetMessageBodyContentAfterAcknoledged ex::" + ex.Message, LoggingLevel.Errors);
        }
    }

我刚刚编写了这个类。我希望这对别人有帮助。

    private class CustomTimer : IDisposable
    {
        private int duration = 1000;
        private Action<object> tick;
        private object obj;
        private Thread thread;
        private bool start = false;
        public CustomTimer(int duration, Action<object> tick)
        {
            this.duration = duration;
            this.tick = tick;
        }
        public void Start(object obj)
        {
            this.obj = obj;
            start = true;
            if (thread == null)
            {
                keepRunning = true;
                thread = new Thread(ThreadMethod);
                thread.Start();
            }
            else
            {
                if (thread.ThreadState == ThreadState.WaitSleepJoin)
                    thread.Interrupt();
            }
        }
        public void Stop()
        {
            if (!start)
                return;
            start = false;
            if (thread.ThreadState == ThreadState.WaitSleepJoin)
                thread.Interrupt();
        }
        public bool IsStopped
        {
            get { return !start; }
        }
        private bool keepRunning = false;
        private void ThreadMethod()
        {
            while (keepRunning)
            {
                if (start)
                {
                    try { Thread.Sleep(duration); } catch { }
                    if (start && keepRunning)
                        tick(this.obj);
                }
                else if(keepRunning)
                {
                    try { Thread.Sleep(int.MaxValue); } catch { }
                }
            }
        }

        public void Dispose()
        {
            this.keepRunning = false;
            this.start = false;
            if (thread.ThreadState == ThreadState.WaitSleepJoin)
                thread.Interrupt();
            if (thread.ThreadState == ThreadState.WaitSleepJoin)
                thread.Interrupt();
        }
    }