代码之家  ›  专栏  ›  技术社区  ›  Tester101

从计时器线程调用GUI线程上的方法

  •  9
  • Tester101  · 技术社区  · 15 年前

    在我的应用程序中,我使用计时器来检查RSS提要中的更新,如果发现新项目,我会弹出一个自定义对话框通知用户。当我手动运行检查时,一切正常,但当自动检查在timers Elapsed事件中运行时,将不显示自定义对话框。

    首先这是一个线程问题吗?(我认为这是因为手动和自动检查都使用相同的代码)。

    我需要在自定义对话类中做些什么吗?

    编辑: 这是一个winforms应用程序。

    下面是一个代码的示例。(请不要在这个代码示例中指出语法错误,这只是一个简单的示例,不是真正的代码)。

    public class MainForm : System.Windows.Forms.Form
    {
        //This is the object that does most of the work.
        ObjectThatDoesWork MyObjectThatDoesWork = new ObjectThatDoesWork(); 
        MyObjectThatDoesWork.NewItemsFound += new NewItemsFoundEventHandler(Found_New_Items);
    
        private void Found_New_Items(object sender, System.EventArgs e)
        {
            //Display custom dialog to alert user.
        }
    
        //Method that doesn't really exist in my class, 
        // but shows that the main form can call Update for a manual check.
        private void Button_Click(object sender, System.EventArgs e)
        {
            MyObjectThatDoesWork.Update();
        }
    
        //The rest of MainForm with boring main form stuff
    }
    
    
    public class ObjectThatDoesWork
    {
        System.Timers.Timer timer;
    
        public ObjectThatDoesWork()
        {
            timer = new System.Timers.Timer();
            timer.Interval = 600000;
            timer.AutoReset = true;
            timer.Elapsed += new new System.Timers.ElapsedEventHandler(TimeToWork);
            timer.Start();
        }
    
        private void TimeToWork(object sender, System.Timers.ElapsedEventArgs e)
        {
            Update();
        }
    
        public void Update()
        {
            //Check for updates and raise an event if new items are found.
            //The event is consumed by the main form.
            OnNewItemsFound(this);
        }
    
        public delgate void NewItemsFoundEventHandler(object sender, System.EventArgs e);
        public event NewItemsFoundEventHandler NewItemsFound;
        protected void OnNewItemsFound(object sender)
        {
            if(NewItemsFound != null)
            {
                NewItemsFound(sender, new System.EventArgs());
            }
        }
    }
    

    在阅读了一些评论和答案之后,我想我的问题是我正在使用 System.Timers.Timer 不是一个 System.Windows.Forms.Timer .

    编辑:

    更改为Forms.Timer后,初始测试看起来不错(但还没有新项,因此还没有看到自定义对话框)。我添加了一些代码,以便在调用update方法时将线程ID输出到文件中。使用Timers.Timer线程ID不是GUI线程,而是使用Forms.Timer线程ID与GUI相同。

    4 回复  |  直到 15 年前
        1
  •  19
  •   Giorgi    15 年前

    Which timer 你在用吗?System.Windows.Forms.Timer自动在UI线程上触发事件。如果你正在使用另一个,你将需要使用 Control.Invoke 调用UI线程上的方法。

        2
  •  1
  •   Daniel MoÅ¡mondor    15 年前

    .Invoke()

        3
  •  0
  •   cordellcp3    15 年前

    你的申请是WPF申请吗?如果是,则必须将工作从后台线程委托给与UI线程关联的调度程序。

    发布一些代码,以便获得更好的帮助并查看Dispatcher类 http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx

        4
  •  0
  •   Koray    12 年前
        private static System.Threading.SynchronizationContext _UI_Context;
        //call this function once from the UI thread
        internal static void init_CallOnUIThread()
        {
            _UI_Context = System.Threading.SynchronizationContext.Current;
        }
        public static void CallOnUIThread(Action action, bool asynchronous = false)
        {
            if (!asynchronous)
                _UI_Context.Send((o) =>
                {
                    action();
                }, null);
            else
                _UI_Context.Post((o) =>
                {
                    action();
                }, null);
        }