2009-02-06 33 views
47

Tôi không thể tìm ra cách làm cho ứng dụng Biểu mẫu C# Windows ghi vào một hộp văn bản từ một chuỗi. Ví dụ trong Program.cs chúng tôi có tiêu chuẩn main() mà rút ra các hình thức:Viết cho một TextBox từ một chủ đề khác?

static void Main() 
{ 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    Application.Run(new Form1()); 
} 

Sau đó, chúng tôi có trong Form1.cs:

public Form1() 
{ 
    InitializeComponent(); 

    new Thread(SampleFunction).Start(); 
} 

public static void SampleFunction() 
{ 
    while(true) 
     WindowsFormsApplication1.Form1.ActiveForm.Text += "hi. "; 
} 

Tôi đi về việc này hoàn toàn sai?

CẬP NHẬT

Đây là mẫu mã làm việc được cung cấp từ bendewey:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     new Thread(SampleFunction).Start(); 
    } 

    public void AppendTextBox(string value) 
    { 
     if (InvokeRequired) 
     { 
      this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); 
      return; 
     } 
     textBox1.Text += value; 
    } 

    void SampleFunction() 
    { 
     // Gets executed on a seperate thread and 
     // doesn't block the UI while sleeping 
     for(int i = 0; i<5; i++) 
     { 
      AppendTextBox("hi. "); 
      Thread.Sleep(1000); 
     } 
    } 
} 

Trả lời

47

On MainForm của bạn làm cho một chức năng để thiết lập các hộp kiểm tra các InvokeRequired

public void AppendTextBox(string value) 
{ 
    if (InvokeRequired) 
    { 
     this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); 
     return; 
    } 
    ActiveForm.Text += value; 
} 

mặc dù trong phương pháp tĩnh của bạn, bạn không thể chỉ gọi.

WindowsFormsApplication1.Form1.AppendTextBox("hi. "); 

bạn phải có một tài liệu tham khảo tĩnh đến Form1 nơi nào đó, nhưng điều này là không thực sự khuyến khích hoặc cần thiết, có thể bạn chỉ cần thực SampleFunction của bạn không phải là tĩnh nếu như vậy thì bạn chỉ có thể gọi

AppendTextBox("hi. "); 

Nó sẽ nối thêm vào một chuỗi khác nhau và được ghép nối với giao diện người dùng bằng cách sử dụng cuộc gọi Gọi nếu cần.

Full Mẫu

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     new Thread(SampleFunction).Start(); 
    } 

    public void AppendTextBox(string value) 
    { 
     if (InvokeRequired) 
     { 
      this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); 
      return; 
     } 
     textBox1.Text += value; 
    } 

    void SampleFunction() 
    { 
     // Gets executed on a seperate thread and 
     // doesn't block the UI while sleeping 
     for(int i = 0; i<5; i++) 
     { 
      AppendTextBox("hi. "); 
      Thread.Sleep(1000); 
     } 
    } 
} 
+0

tôi đã cố gắng mã của bạn, và nó không hoàn toàn làm việc cho tôi. Tôi đánh giá cao người bạn đời trả lời. –

+0

Cụ thể hơn, nó biên dịch, nhưng TextBox không liên tục được ghi vào. –

+0

Bạn có thể đăng mã bạn đang thử không? – bendewey

1

Có một cái nhìn tại Control.BeginInvoke phương pháp. Vấn đề là không bao giờ cập nhật các điều khiển UI từ một luồng khác. BeginInvoke sẽ gửi cuộc gọi đến chuỗi giao diện người dùng của điều khiển (trong trường hợp của bạn, Biểu mẫu).

Để lấy biểu mẫu, hãy xóa công cụ sửa đổi tĩnh khỏi hàm mẫu và sử dụng hàm này.BeginInvoke() như được hiển thị trong ví dụ từ MSDN.

13

hoặc bạn có thể làm như

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     new Thread(SampleFunction).Start(); 
    } 

    void SampleFunction() 
    { 
     // Gets executed on a seperate thread and 
     // doesn't block the UI while sleeping 
     for (int i = 0; i < 5; i++) 
     { 
      this.Invoke((MethodInvoker)delegate() 
      { 
       textBox1.Text += "hi"; 
      }); 
      Thread.Sleep(1000); 
     } 
    } 
} 
2

gì thậm chí còn dễ dàng hơn là chỉ cần sử dụng điều khiển BackgroundWorker ...

4

Bạn cần phải thực hiện các hành động từ thread sở hữu kiểm soát.

Đó là cách tôi làm điều đó mà không cần thêm quá nhiều tiếng ồn mã:

control.Invoke(() => textBox1.Text += "hi"); 

đâu quá tải Gọi là một phần mở rộng đơn giản từ Lokad Shared Libraries:

/// <summary> 
/// Invokes the specified <paramref name="action"/> on the thread that owns  
/// the <paramref name="control"/>.</summary> 
/// <typeparam name="TControl">type of the control to work with</typeparam> 
/// <param name="control">The control to execute action against.</param> 
/// <param name="action">The action to on the thread of the control.</param> 
public static void Invoke<TControl>(this TControl control, Action action) 
    where TControl : Control 
{ 
    if (!control.InvokeRequired) 
    { 
    action(); 
    } 
    else 
    { 
    control.Invoke(action); 
    } 
} 
10

Tôi sẽ sử dụng BeginInvoke thay vì Invoke như thường xuyên nhất có thể, trừ khi bạn thực sự cần phải chờ cho đến khi kiểm soát của bạn được cập nhật (trong ví dụ của bạn không phải là trường hợp).BeginInvoke đăng các đại biểu trên hàng đợi tin nhắn WinForms và cho phép mã gọi điện thoại tiến hành ngay lập tức (trong trường hợp của bạn cho vòng lặp trong SampleFunction). Invoke không chỉ đăng bài các đại biểu, nhưng cũng chờ đợi cho đến khi nó đã được hoàn thành.

Vì vậy, trong phương pháp AppendTextBox từ ví dụ của bạn, bạn sẽ thay thế Invoke với BeginInvoke như thế:

public void AppendTextBox(string value) 
{ 
    if (InvokeRequired) 
    { 
     this.BeginInvoke(new Action<string>(AppendTextBox), new object[] {value}); 
     return; 
    } 
    textBox1.Text += value; 
} 

Vâng và nếu bạn muốn nhận được thậm chí nhiều hơn tưởng tượng, đó cũng là lớp SynchronizationContext, cho phép bạn cơ bản làm tương tự như Control.Invoke/Control.BeginInvoke, nhưng với lợi thế là không cần một tham chiếu điều khiển WinForms để được biết đến. Here là một hướng dẫn nhỏ trên SynchronizationContext.

3

đơn giản nhất, mà không cần quan tâm đến các đại biểu

if(textBox1.InvokeRequired == true) 
    textBox1.Invoke((MethodInvoker)delegate { textBox1.Text = "Invoke was needed";}); 

else 
    textBox1.Text = "Invoke was NOT needed"; 
2

Dưới đây là những gì tôi đã thực hiện để tránh CrossThreadException và văn bản cho textbox từ thread khác.

Đây là chức năng nhấn nút của tôi- Tôi muốn tạo một số lượng ngẫu nhiên các chuỗi và sau đó nhận ID của chúng bằng cách gọi getID(); phương thức và giá trị textBox khi đang ở trong chuỗi công nhân đó.

private void btnAppend_Click(object sender, EventArgs e) { 

     Random n = new Random(); 

     for (int i = 0; i < n.Next(1,5); i++) 
     { 
      label2.Text = "UI Id" + ((Thread.CurrentThread.ManagedThreadId).ToString()); 
      Thread t = new Thread(getId); 
      t.Start(); 
     } 

    } 

Đây là getId (workerThread) mã

public void getId() 
    { 
     int id = Thread.CurrentThread.ManagedThreadId; 
     //Note that, I have collected threadId just before calling 
     //*this.Invoke* 
     //method else it would be same as of UI thread inside the below code 
     //block 
     this.Invoke((MethodInvoker)delegate() 
     { 
      inpTxt.Text += "My id is" +"--"+id+Environment.NewLine; 
     }); 
Các vấn đề liên quan