Почему событие отметки времени в новом классе вызывает метод из 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++;
        }
    }
}

Как только я вызываю метод CombindedStringFix в методе Start в классе, который он работает, и выполняет все строки в CombindedStringFix. Я использовал breakpoiont, и он делает все.

Но в следующий раз, когда он вызывает метод в событии отметки таймера в новом классе, я использовал точку останова и после того, как он выполнил первую строку BegingUpdate(); он просто ограничивается и никогда не останавливается в событии таймера и никогда не будет продолжать работу над BeginUpdate();

Даже если я удалю BeginUpdate(); поэтому он будет делать первую строку, а затем продолжить, она никогда не переместится на следующую строку/с.

Я видел теперь, что я получаю исключение в событии таймера:

Неверная операция поперечного потока: элемент управления 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.

Теги:
winforms

2 ответа

0
Лучший ответ

Вероятно, проблема заключается в том, что существует исключение, которое происходит где-то в вашем истекшем событии, и таймер никогда не запускается снова. Вы можете установить точку останова и следовать ей, чтобы в первый раз войти, чтобы увидеть, где/если она терпит неудачу. Кроме того, вы можете запрограммировать его, чтобы начать резервное копирование независимо:

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

Поскольку вы подтвердили, что происходит перекрестное потоковое исключение, я бы рекомендовал прочитать:

Как сделать безопасные вызовы для 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  
        // 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
    Маверик, ты прав. Это исключение, которое я получаю: Операция между потоками недопустима: доступ к элементу управления Form1 осуществляется из потока, отличного от потока, в котором он был создан
  • 0
    @SharonGetter - в своем ответе я добавил некоторые пояснения для многопоточных вызовов для вас. Он имеет ссылку на MSDN вместе с их демо.
Показать ещё 4 комментария
0

Я попытаюсь ответить на это, но без полного контекста это немного грубо.

  1. Я замечаю, что в CombindedStringFix() вас есть то, что похоже на объект таймера, называемый timer3. Имя этого таймера не похоже на имя вашего таймера в классе SaveOldHtml, и я не вижу свойство/поле, открытое этим именем. Мне интересно, есть ли у вас два таймера, которые могут быть смущены.

Я знаю, что это плохая форма, чтобы не отвечать на вопрос, но в отсутствие более специфических/более источников это лучшее, что я могу собрать. Любой контекст, и я могу предложить больше помощи!

  • 0
    Таймер в form1 в CombindedStringFix - timer3, он в моем конструкторе form1 и делает что-то еще. это работает и не связано с этой проблемой.
  • 0
    Отметьте, как я могу загрузить или отредактировать свой вопрос в полном контексте, чего не хватает?
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню