首页 文章

为什么新类中的计时器tick事件会从form1调用一次方法,并且在下一次它什么都不做的时候?

提问于
浏览
1

在form1我有这个公共方法:

public void CombindedStringFix()
        {
            BeginUpdate();

            label3.Text = SaveOldHtml.HtmlLoadedFileNumber.ToString();
            richTextBox1.Clear();
            List<string> newText1 = new List<string>();
            label1.Select();
            scrollerList = new List<string>(Filters.newTextWithoutLinks);
            scrollerText = string.Join(Environment.NewLine, scrollerList);
            scroller1.TextToScroll = scrollerText;
            combindedString = string.Join(Environment.NewLine, SaveOldHtml.newText);
            richTextBox1.Text = combindedString;            
            string[] rlines = richTextBox1.Lines;
            timer3.Start();
            richTextBox1.SelectionStart = 0;
            richTextBox1.SelectionLength = rlines[0].Length;
            richTextBox1.SelectionColor = Color.Red;
            richTextBox1.Select(rlines[0].Length, rlines[1].Length + 1);
            richTextBox1.SelectionColor = Color.Green;

            EndUpdate();
        }

然后在新类我调用这个方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Timers;
using System.Windows.Forms;

namespace ScrollLabelTest
{

    class SaveOldHtml
    {
        private static Form1 frm1 = null;
        private static int count;
        private static System.Timers.Timer _timer = new System.Timers.Timer();
        private static string page;
        public static List<string> newText = new List<string>();
        public static int HtmlLoadedFileNumber = 0;

        public SaveOldHtml(string DirectoryToSave,int count, string contents)
        {
            System.IO.File.WriteAllText(DirectoryToSave + "Page" + count.ToString("D6")
                                        + ".html", contents);
        }

        public SaveOldHtml(string DirectoryToSave, List<string> newTextList, int count)
        {
            using (StreamWriter myStream = new StreamWriter(DirectoryToSave + "newTextList" + count.ToString("D6")
                                        + ".txt"))
            {
                for (int i = 0; i < newTextList.Count; i++)
                {
                    myStream.WriteLine(newTextList[i]);
                }

            }
        }

        public static void Start(Form1 form)
        {
            frm1 = form;
            _timer.Elapsed += _timer_Elapsed;
            _timer.Interval = 10000;
            count = 5;
            LoadOldHtmlFiles();
            frm1.CombindedStringFix();
            _timer.Start();
        }

        static void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _timer.Stop();
            LoadOldHtmlFiles();
            frm1.CombindedStringFix();
            _timer.Start();
        }

        private static void LoadOldHtmlFiles()
        {

            page = File.ReadAllText(@"c:\temp\OldHtml\page" + count.ToString("D6") + ".html");
            ListsExtractions.OffExtractions(@"c:\temp\OldHtml\page" + count.ToString("D6") + ".html", page, newText);
            count ++;
            HtmlLoadedFileNumber++;
        }
    }
}

一旦我在类的Start方法中调用CombindedStringFix方法,它就可以正常工作并完成CombindedStringFix中的所有行 . 我使用了一个breakpoiont,它做到了这一切 .

但是下次当它在新类中调用计时器tick事件中的方法时,我使用断点并且一旦它在第一行BegingUpdate();它只是contine而且永远不会在计时器tick事件中再次停止,并且永远不会超越BeginUpdate();

即使我删除了BeginUpdate();所以它将成为第一行,然后继续它将永远不会移动到下一行/ s .

我现在看到我在计时器刻度事件中遇到异常:

跨线程操作无效:控制从其创建的线程以外的线程访问的“Form1”

System.InvalidOperationException was caught
  HResult=-2146233079
  Message=Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Control.get_Handle()
       at ScrollLabelTest.Form1.BeginUpdate() in e:\scrolllabel\ScrollLabel\ScrollLabel\Form1.cs:line 69
       at ScrollLabelTest.Form1.CombindedStringFix() in e:\scrolllabel\ScrollLabel\ScrollLabel\Form1.cs:line 280
       at ScrollLabelTest.SaveOldHtml._timer_Elapsed(Object sender, ElapsedEventArgs e) in e:\scrolllabel\ScrollLabel\ScrollLabel\SaveOldHtml.cs:line 64
  InnerException:

我想这与frm1变量有关 .

2 回答

  • 0

    问题很可能是在Elapsed事件中某处发生了异常,并且Timer永远不会再次启动 . 您可以设置一个断点,并在第一次进入时查看断点,以查看它是否失败 . 或者,您可以将其编码为开始备份,无论如何:

    static void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        _timer.Stop();
    
        try
        {
            LoadOldHtmlFiles();
            frm1.CombindedStringFix();
        }
        catch (Exception ex)
        {
            // do something (or nothing) with the exception
        }
        finally 
        {
            _timer.Start();
        }
    }
    

    由于您确认发生了跨线程异常,我建议您阅读:

    How to: Make Thread-Safe Calls to Windows Forms Controls

    这是他们的演示,以防链接被破坏:

    using System;
    using System.ComponentModel;
    using System.Threading;
    using System.Windows.Forms;
    
    namespace CrossThreadDemo
    {
        public class Form1 : Form
        {
            // This delegate enables asynchronous calls for setting 
            // the text property on a TextBox control. 
            delegate void SetTextCallback(string text);
    
            // This thread is used to demonstrate both thread-safe and 
            // unsafe ways to call a Windows Forms control. 
            private Thread demoThread = null;
    
            // This BackgroundWorker is used to demonstrate the  
            // preferred way of performing asynchronous operations. 
            private BackgroundWorker backgroundWorker1;
    
            private TextBox textBox1;
            private Button setTextUnsafeBtn;
            private Button setTextSafeBtn;
            private Button setTextBackgroundWorkerBtn;
    
            private System.ComponentModel.IContainer components = null;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            // This event handler creates a thread that calls a  
            // Windows Forms control in an unsafe way. 
            private void setTextUnsafeBtn_Click(
                object sender, 
                EventArgs e)
            {
                this.demoThread = 
                    new Thread(new ThreadStart(this.ThreadProcUnsafe));
    
                this.demoThread.Start();
            }
    
            // This method is executed on the worker thread and makes 
            // an unsafe call on the TextBox control. 
            private void ThreadProcUnsafe()
            {
                this.textBox1.Text = "This text was set unsafely.";
            }
    
            // This event handler creates a thread that calls a  
            // Windows Forms control in a thread-safe way. 
            private void setTextSafeBtn_Click(
                object sender, 
                EventArgs e)
            {
                this.demoThread = 
                    new Thread(new ThreadStart(this.ThreadProcSafe));
    
                this.demoThread.Start();
            }
    
            // This method is executed on the worker thread and makes 
            // a thread-safe call on the TextBox control. 
            private void ThreadProcSafe()
            {
                this.SetText("This text was set safely.");
            }
    
            // This method demonstrates a pattern for making thread-safe 
            // calls on a Windows Forms control.  
            // 
            // If the calling thread is different from the thread that 
            // created the TextBox control, this method creates a 
            // SetTextCallback and calls itself asynchronously using the 
            // Invoke method. 
            // 
            // If the calling thread is the same as the thread that created 
            // the TextBox control, the Text property is set directly.  
    
            private void SetText(string text)
            {
                // InvokeRequired required compares the thread ID of the 
                // calling thread to the thread ID of the creating thread. 
                // If these threads are different, it returns true. 
                if (this.textBox1.InvokeRequired)
                {   
                    SetTextCallback d = new SetTextCallback(SetText);
                    this.Invoke(d, new object[] { text });
                }
                else
                {
                    this.textBox1.Text = text;
                }
            }
    
            // This event handler starts the form's  
            // BackgroundWorker by calling RunWorkerAsync. 
            // 
            // The Text property of the TextBox control is set 
            // when the BackgroundWorker raises the RunWorkerCompleted 
            // event. 
            private void setTextBackgroundWorkerBtn_Click(
                object sender, 
                EventArgs e)
            {
                this.backgroundWorker1.RunWorkerAsync();
            }
    
            // This event handler sets the Text property of the TextBox 
            // control. It is called on the thread that created the  
            // TextBox control, so the call is thread-safe. 
            // 
            // BackgroundWorker is the preferred way to perform asynchronous 
            // operations. 
    
            private void backgroundWorker1_RunWorkerCompleted(
                object sender, 
                RunWorkerCompletedEventArgs e)
            {
                this.textBox1.Text = 
                    "This text was set safely by BackgroundWorker.";
            }
    
            #region Windows Form Designer generated code
    
            private void InitializeComponent()
            {
                this.textBox1 = new System.Windows.Forms.TextBox();
                this.setTextUnsafeBtn = new System.Windows.Forms.Button();
                this.setTextSafeBtn = new System.Windows.Forms.Button();
                this.setTextBackgroundWorkerBtn = new System.Windows.Forms.Button();
                this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
                this.SuspendLayout();
                //  
                // textBox1 
                //  
                this.textBox1.Location = new System.Drawing.Point(12, 12);
                this.textBox1.Name = "textBox1";
                this.textBox1.Size = new System.Drawing.Size(240, 20);
                this.textBox1.TabIndex = 0;
                //  
                // setTextUnsafeBtn 
                //  
                this.setTextUnsafeBtn.Location = new System.Drawing.Point(15, 55);
                this.setTextUnsafeBtn.Name = "setTextUnsafeBtn";
                this.setTextUnsafeBtn.TabIndex = 1;
                this.setTextUnsafeBtn.Text = "Unsafe Call";
                this.setTextUnsafeBtn.Click += new System.EventHandler(this.setTextUnsafeBtn_Click);
                //  
                // setTextSafeBtn 
                //  
                this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);
                this.setTextSafeBtn.Name = "setTextSafeBtn";
                this.setTextSafeBtn.TabIndex = 2;
                this.setTextSafeBtn.Text = "Safe Call";
                this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);
                //  
                // setTextBackgroundWorkerBtn 
                //  
                this.setTextBackgroundWorkerBtn.Location = new System.Drawing.Point(177, 55);
                this.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn";
                this.setTextBackgroundWorkerBtn.TabIndex = 3;
                this.setTextBackgroundWorkerBtn.Text = "Safe BW Call";
                this.setTextBackgroundWorkerBtn.Click += new System.EventHandler(this.setTextBackgroundWorkerBtn_Click);
                //  
                // backgroundWorker1 
                //  
                this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
                //  
                // Form1 
                //  
                this.ClientSize = new System.Drawing.Size(268, 96);
                this.Controls.Add(this.setTextBackgroundWorkerBtn);
                this.Controls.Add(this.setTextSafeBtn);
                this.Controls.Add(this.setTextUnsafeBtn);
                this.Controls.Add(this.textBox1);
                this.Name = "Form1";
                this.Text = "Form1";
                this.ResumeLayout(false);
                this.PerformLayout();
    
            }
    
            #endregion
    
    
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.Run(new Form1());
            }
    
        }
    }
    
  • 0

    我将尝试回答这个问题,但如果没有完整的背景,那就有点粗糙了 .

    • 我注意到在 CombindedStringFix() 方法中你看起来像是一个名为 timer3 的计时器对象 . 此计时器的名称似乎与 SaveOldHtml 类中的计时器名称不匹配,我想知道您是否有两个可能会混淆的计时器 .

    我知道不回答这个问题是不好的形式,但是如果没有更多细节/更多来源,这是我能够集合的最好的 . 任何更多的背景,我可以提供更多的帮助!

相关问题