使用 Windows 窗体计时器从不同的类中触发方法

本文关键字:方法 窗体 Windows 计时器 使用 | 更新日期: 2023-09-27 18:30:15

抱歉,如果已经有答案了,但我挖了很多,发现的很少。

我正在尝试在 C# .NET 4.5 Windows 窗体应用程序上实现一个看门狗系统。 基本上,我有一个带有各种按钮、文本显示等的表单,可以连接到外部设备。 我在主窗体上有一个计时器,应该每 250 毫秒左右检查一次设备是否有变化。

我将所有 MainPage 表单代码(包括计时器)集中到一个类中,并将外部设备的代码集中到从 MainPage 继承的自己的类中。 问题是,我希望能够让计时器的 Tick() 函数调用 Device 类的方法。 以下是简化的代码:

namespace MyApplication
{
    public partial class MainPage : Form
    {
        public MainPage()
        {
            InitializeComponent();
        }
        public static void SetTextBox(string Message)
        {
            Textbox_Status.Text = Message;
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            Device.DeviceCheck();
        }
    }
    public class Device : MainPage
    {
        public void DeviceCheck()
        { 
            //Do other stuff here
            SetTextBox("Some text");
        }
    }
}

当然,我不能从计时器中调用Device.DeviceCheck,因为它不是静态的。 但是,如果我声明 DeviceCheck 静态,我现在会收到一个错误,指出Textbox_Status不是静态的。 如果我试图声明它是静态的,Visual Studio会非常生我的气!

最初,我将所有内容都转储到同一个类中,并且一切正常,但这是非常丑陋的代码。 有没有更好的方法?

编辑:额外的障碍=需要由DeviceCheck()更改的形式中的多个事物

所以我在简化的代码中省略了什么:除了 SetTextBox() 方法之外,我还有一个基于来自 DeviceCheck 的信息设置一些指标的方法:

    public void SetImages(string Image)
    {
        switch(Image)
        {
            case "Green":
                Image_BlackDim.Visible = true;
                Image_RedDim.Visible = true;
                Image_GreenDim.Visible = false;
                break;
            case "Red":
                Image_BlackDataKeyDim.Visible = true;
                Image_RedDataKeyDim.Visible = false;
                Image_GreenDataKeyDim.Visible = true;
                break;
            case "Black":
                Image_BlackDim.Visible = false;
                Image_RedDim.Visible = true;
                Image_GreenDim.Visible = true;
                break;
            case "None":
            default:
                Image_BlackDim.Visible = true;
                Image_RedDim.Visible = true;
                Image_GreenDim.Visible = true;
                break;
        }
    }

当然,当我构建表单时,我的所有指标也都已到位,因此它们也不能是静态的。 因此,DeviceCheck返回要显示的字符串消息是有效的,但我不能真正让它也返回SetImages()使用的字符串。

井。。。我可以通过返回具有多个字符串的结构来,但是有更好的方法吗?

编辑:这是我的工作解决方案,基于埃里克的建议:

我从状态元素的结构开始:

public struct Dev_status
    {
        public string Indicator1;
        public string Indicator2;
        public DK_status(string indicator1, string indicator1)
        {
            this.Indicator1 = indicator1;
            this.Indicator2 = indicator2;
        }
    }
    public static Dev_status status = new Dev_status(Device.Messages.thing1_offline,Device.Messages.thing2_offline);

指标现在从status获取消息:

    public void SetStatusBoxes()
    {
        Textbox_thing1_Status.Text = status.Indicator1;
        Textbox_thing2_Status.Text = status.Indicator2;
    }
    public void SetImages()
    {
        string IndicatorColor = "None";
        if (status.Indicator2 == Device.Messages.GreenThing) IndicatorColor = "Green";
        else if (status.Indicator2 == Device.Messages.RedThing) IndicatorColor = "Red";
        else if (status.Indicator2 == Device.Messages.BlackThing) IndicatorColor = "Black";
        switch(IndicatorColor)
        {
            case "Green":
                Image_BlackDim.Visible = true;
                Image_RedDim.Visible = true;
                Image_GreenDim.Visible = false;
                break;
            case "Red":
                Image_BlackDim.Visible = true;
                Image_RedDim.Visible = false;
                Image_GreenDim.Visible = true;
                break;
            case "Black":
                Image_BlackDim.Visible = false;
                Image_RedDim.Visible = true;
                Image_GreenDim.Visible = true;
                break;
            case "None":
            default:
                Image_BlackDim.Visible = true;
                Image_RedDim.Visible = true;
                Image_GreenDim.Visible = true;
                break;
        }
    }

计时器只是调用 DeviceCheck 方法并设置指标:

    private void timer1_Tick(object sender, EventArgs e)
    {
        status = Device.DeviceCheck();
        SetStatusBoxes();
        SetImages();
    }

最后,DeviceCheck为状态结构设置值,该结构是公共的、静态的,并由 Device 类继承:

    public static void DeviceCheck()
    {
        //Code that checks the device status
        status.Indicator1 = CheckDeviceConnected();
        status.Indicator2 = CheckDeviceType();
    }

这非常无缝地工作。 最后,我毕竟不需要从DeviceCheck返回值。 不过,我仍然会将这个想法标记为被接受,因为它将我引向了正确的方向。

使用 Windows 窗体计时器从不同的类中触发方法

如果你

1)让DeviceCheck()在文本框中返回您想要的字符串(而不是设置文本框)

2) 在 timer1_Tick() 中,使用来自 DeviceCheck 的返回值设置文本框。

喜欢这个:

namespace MyApplication
{
    public partial class MainPage : Form
    {
        public MainPage()
        {
            InitializeComponent();
        }
        public static void SetTextBox(string Message)
        {
            Textbox_Status.Text = Message;
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            string result = Device.DeviceCheck();
            SetTextBox(result);
        }
    }
    public class Device : MainPage
    {
        public string DeviceCheck()
        { 
            //Do other stuff here
            return("Some text");
        }
    }
}

我在这里看到了两个明显的选择:将DeviceCheck()声明为子类要实现的抽象方法,或者以某种方式公开计时器tick事件。

抽象方法:

public partial abstract class MainPage : Form
{
    public MainPage()
    {
        InitializeComponent();
    }
    public void SetTextBox(string message)
    {
        Textbox_Status.Text = message;
    }
    protected abstract void DeviceCheck();
    private void timer1_Tick(object sender, EventArgs e)
    {
        DeviceCheck();
    }
}
public class Device : MainPage
{
    public void DeviceCheck()
    { 
        //Do other stuff here
        SetTextBox("Some text");
    }
}

事件:

public partial abstract class MainPage : Form
{
    public MainPage()
    {
        InitializeComponent();
    }
    public void SetTextBox(string message)
    {
        Textbox_Status.Text = message;
    }
   protected event EventHandler TimerTick;
    private void timer1_Tick(object sender, EventArgs e)
    {
        EventHandler handler = TimerTick;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}
public class Device : MainPage
{
    public Device()
    {
        TimerTick += (sender, e) => DeviceCheck();
    }
    public void DeviceCheck()
    { 
        //Do other stuff here
        SetTextBox("Some text");
    }
}

另一个建议的答案也应该有效,假设static已从SetTextBox()方法中删除。但是根据您的评论,听起来消息处理(即string值)只是您想要执行的操作的一部分。不过,您仍然可以遵循该建议,但是您将传递某种聚合对象而不是string,即具有多个属性的简单容器类,包括消息string和您需要的任何其他值。