【问题标题】:Issue with System.Threading.Timer and Modal ShowDialog()System.Threading.Timer 和模态 ShowDialog() 的问题
【发布时间】:2017-01-11 14:59:01
【问题描述】:

我有一个应用程序,其中我正在初始化一个Windows Form 和一个System.Threading.Timer 的类。

如果timer(不断检查某些基于IPC 的内容)遇到特定值,它会发出同一类中的event 信号,然后在之前初始化的对话框中调用ShowDialog()

不幸的是,这个ShowDialog()Modal,停止了计时器。

我的印象是System.Threaded.Timer 是在与调用线程不同的线程中创建的,因此 Timer 将继续在后台运行。

编辑 - 一些代码

public delegate void EventHandler();
class someClass
{
    WrapperForm dlg = null;
    public void CallToChildThread(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        //Check IPC
        //Fire event
        _show.Invoke();
    }
    public someClass()
    {
        public static event EventHandler _show;
        initializeDialog(); // Initialize the dialog. Standard new
        var autoEvent = new AutoResetEvent(false);
        var stateTimer = new System.Threading.Timer(CallToChildThread,
                                   autoEvent, 1000, 250);
        _show += new EventHandler(eventCheck);
    }
    void eventCheck()
    {
        //If some condition
        dlg.ShowDialog(); //Timer stops
    }
}

如何解决?

【问题讨论】:

  • 如果你能让我们看看你尝试了什么(一些代码),那就太好了。
  • 模式不会为我暂停计时器 o.O
  • 我做了一些更改,以便反映您的代码,希望对您有所帮助。

标签: c# multithreading winforms timer


【解决方案1】:

System.Threading.Timer 类有一个已知问题,如果你不保留对它的引用,即使在运行时它也会被垃圾收集器收集。

切换到使用 System.Timers.Timer,它只是 System.Threading.Timer 的包装器,或者保留对计时器的引用,这样 GC 就不会收集它并取消您的计时器。

public delegate void EventHandler();
class someClass
{
    WrapperForm dlg = null;
    System.Threading.Timer stateTimer;
    public static event EventHandler _show;

    public void CallToChildThread(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        //Check IPC
        //Fire event
        _show.Invoke();
    }
    public someClass()
    {
        initializeDialog(); // Initialize the dialog. Standard new
        var autoEvent = new AutoResetEvent(false);
        stateTimer = new System.Threading.Timer(CallToChildThread,
                                   autoEvent, 1000, 250);
        _show += new EventHandler(eventCheck);
    }
    void eventCheck()
    {
        //If some condition
        dlg.ShowDialog();
    }
}

【讨论】:

  • 啊,这就是问题所在。用System.Timers.Timer 替换它就可以了。谢谢你。 System.Threading.Timer 的问题是众所周知的吗?
【解决方案2】:

用你的代码我改变了我的例子,我现在正在使用你的计时器(我仍在使用我的计时器,所以我可以看到另一个计时器仍在运行)

public partial class Form1 : Form
    {
        Form frm1 = new Form();
        int i;
        private System.Threading.Timer t;
        //If the problem is garbage collecting then the line above is very important.
        public Form1()
        {
            InitializeComponent();
            var autoEvent = new AutoResetEvent(false);
            var stateTimer = new System.Threading.Timer(CallToChildThread,
                                   autoEvent, 1000, 250);
        }
    private void CallToChildThread(object state)
    {
        i++;
        //Updating value here, update in other timer (this is to avoid crossthreadEx)   
    }

    private void button1_Click(object sender, EventArgs e)
    {
        frm1.ShowDialog();
        //Label keeps updating!
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        label1.Text = i.ToString();
    }
}

它仍然对我有用,原因可能是因为我没有将计时器设为局部变量,而是在类中声明它。

【讨论】:

  • 您在测试中使用了错误类型的计时器,System.Threading.Timer 没有Tick 事件,它使用委托回调。
  • 我添加了一些代码。 System.Threading.Timer 没有 Enabled 属性。
猜你喜欢
  • 1970-01-01
  • 2011-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
  • 2022-10-15
  • 2011-05-11
相关资源
最近更新 更多