2015-06-20 2 views
2

Итак, я делаю приложение C#, которое должно непрерывно читать и отображать содержимое текстового файла, позволяя пользователю вводить что-то в текстовое поле и добавлять его в конец это очень файл.Невозможно изменить переменные из отдельного потока

Я делаю это, запустив мой метод read в отдельном потоке, однако изменение переменной, которая хранит содержимое текстовых файлов дисплея, вызывает проблемы. Первоначально я пробовал использовать метод, который сделал это, однако это не работает и дало ошибку «cross-thread-operation-not-valid». Затем я попытался применить некоторый код, который я нашел в MSDN, но теперь после обновления переменной после завершения потока!

Пожалуйста, помогите.

partial class MainForm 
{ 
    delegate void SetTextCallback(string text); 
    public static string msg; 
    public static string name; 
    public void InitClient() 
    { 
     name = "public.txt"; 
     Console.WriteLine(name); 
     if(!File.Exists(name)) 
     { 
      File.Create(name); 
      File.AppendAllText(name, "Welcome to " + name); 
     } 
     Thread Read = new Thread(new ThreadStart(this.Client)); 
     Read.Start(); 
     while(!Read.IsAlive); 
    } 
    public void WriteText() 
    { 
     File.AppendAllText(name, this.InputBox.Text); 
     this.InputBox.Clear(); 
    } 
    private void SetText(string text) 
    { 
     if (this.OutPut.InvokeRequired) 
     {  
      SetTextCallback d = new SetTextCallback(SetText); 
      this.Invoke(d, new object[] { text }); 
     } 
     else 
     { 
      this.OutPut.Text = text; 
     } 
    } 
    public void Client() 
    { 
     msg = File.ReadAllText(name); 
     Console.WriteLine(msg); 
     Thread.Sleep(300); 
     this.SetText(msg); 
    } 
} 

Почему так ведет себя эта нить. Как изменить код, чтобы содержимое окна вывода всегда равнялось содержимому текстового файла.

Любые предложения приветствуются.

+1

'Client()' - метод с одним выстрелом. Конечно, он завершится после 1 действия, нет петли. –

+0

Это правильное поведение, любые связанные с контролем данные должны быть изменены в контексте потока пользовательского интерфейса, вы не можете сделать это ни на одном другом потоке, здесь, как я вижу, следующий код в методе SetText будет проблемой - this.OutPut.Текст = текст; вы пытаетесь изменить элемент управления пользовательского интерфейса в отдельном потоке –

+0

@MrinalKamboj - эта часть 'else' будет удалена только после того, как она была (рекурсивно) вызвана. Метод SetText здесь правильный. –

ответ

1

У вас есть несколько проблем здесь,

  • использование файла, вероятно, не поточно-.
  • ваш метод не повторяет
  • вашему, Sleep() ИНГ на тему

Вы можете решить все из них канав тему и использовать простой таймер.

+0

Если я повторю этот метод, приложение зависает, возможно, должно было упоминаться об этом. Используя время, я могу заставить его работать. Спасибо – Monacraft

+0

Не лучший вариант TPL, а не простой System.Threading –

+0

Или BackgroundWorker (см. Мой ответ) – havardhu

1

Попробуйте использовать рабочий стол вместо создания нового потока. Фоновый работник будет запускать свой контент в отдельном потоке и позволяет сообщать «прогресс» во время его работы. Этот отчет о ходе выполнения всегда будет выполняться в пользовательском потоке (или потоке, который запустил фоновый рабочий).

У этого события также есть событие, которое вызывается, когда работник фона закончен. Это также выполняется в потоке пользовательского интерфейса.

Этот пример должен помочь вам начать работу.

Update: Добавлены некоторые очень простая обработка ошибок, как предложено

Идея заключается в том, чтобы использовать UserData (второй аргумент) из ReportProgress делать обновление в потоке пользовательского интерфейса, когда вам нужно. В этом случае это строка, но это может быть любой объект.

Кроме того, вы можете использовать Результат DoWorkEventArgs для получения окончательного результата из фоновой работы. В этом случае я возвращаю любое исключение, которое было выбрано, или null в противном случае, но вы можете вернуть все, что хотите здесь.

Это, как отметил Хенк в своем комментарии, очень важно обрабатывать ошибки, возникающие внутри обратного вызова DoWork, потому что исключения и т. Д., Которые здесь происходят, будут проглатываться, и рабочий завершится так, как будто ничего плохого не произошло.

private BackgroundWorker _backgroundWorker; 

public Form1() 
{ 
    InitializeComponent(); 

    _backgroundWorker = new BackgroundWorker(); 
    _backgroundWorker.WorkerReportsProgress = true; 
    _backgroundWorker.WorkerSupportsCancellation = true; 
    // This is the background thread 
    _backgroundWorker.DoWork += BackgroundWorkerOnDoWork; 

    // Called when you report progress 
    _backgroundWorker.ProgressChanged += BackgroundWorkerOnProgressChanged; 

    // Called when the worker is done 
    _backgroundWorker.RunWorkerCompleted += BackgroundWorkerOnRunWorkerCompleted; 
} 

private void BackgroundWorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs) 
{ 
    if (runWorkerCompletedEventArgs.Result != null) 
    { 
     // Handle error or throw it 
     throw runWorkerCompletedEventArgs.Result as Exception; 
    } 

    textBox1.Text = "Worker completed"; 
} 

private void BackgroundWorkerOnProgressChanged(object sender, ProgressChangedEventArgs progressChangedEventArgs) 
{ 
    textBox1.Text = progressChangedEventArgs.UserState as string; 
} 

private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs) 
{ 
    try 
    { 
     for (int i = 0; i < 100 && !_backgroundWorker.CancellationPending; i++) 
     { 
      _backgroundWorker.ReportProgress(0, i + " cycles"); 
      Thread.Sleep(100); 
     } 
    } 
    catch (Exception ex) 
    { 
     doWorkEventArgs.Result = ex; 
    } 

} 

private void startButton_Click(object sender, EventArgs e) 
{ 
    if (!_backgroundWorker.IsBusy) 
     _backgroundWorker.RunWorkerAsync(); 
} 

private void cancelButton_Click(object sender, EventArgs e) 
{ 
    if(_backgroundWorker.IsBusy) 
     _backgroundWorker.CancelAsync(); 
} 
+0

Это все еще 'Sleep()' s на Thread, но это небольшая проблема. Оставляя всю обработку ошибок более серьезной, это приводит к тому, что «это не работает, но нет ошибки». –

+0

@HenkHolterman Это просто пример того, как работает фоновый рабочий, сон не имеет значения. Хорошая точка re: обработка ошибок, хотя, будет обновляться – havardhu

+0

Обработка ошибок уже является частью Bgw, например, [мой ответ здесь] (http://stackoverflow.com/a/30707076/60761). –

Смежные вопросы