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

时间:2013-06-03 06:10:23

标签: c# class timer event-handling

我在类中有一个方法,它从/向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事件/从_timerAutoset事件返回?

7 个答案:

答案 0 :(得分:10)

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

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)
{
   // (...)
}

(当委托访问封闭块中的局部变量时,必须注意。仔细检查代码以确保存储在这些变量中的值在事件处理程序的赋值和此处理程序的调用之间不会发生变化)

答案 1 :(得分:2)

看来这些参数来自其他地方。一种方法是通过callback通过delegate并使用它来获取更新后的值。

另一种方法是制作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
        */
    }
}

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

答案 2 :(得分:1)

您可以尝试使用lambda表达式插入额外的争论..

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

您的方法就像

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

答案 3 :(得分:0)

你可以在课堂上初始化它们,所以所有方法都可以访问它们......

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

对于数据交换,可以在启动ScheduledWorker时将对象变量传递给后台操作,也可以在ScheduledWorker运行时更改对象变量。在后台程序中,可以通过 DoScheduledWorkEventArgs.Argument 调用此对象。可以通过 DoScheduledWorkEventArgs.SignalTime 属性调用引发DoWork事件的时间。 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; }
    }
}

答案 6 :(得分:0)

我刚刚编写了这门课程。我希望对别人有所帮助。

{{1}}