2009-07-09 73 views
0

我正在爲我的Windows窗體應用程序創建線程安全控件。線程安全控制 - 崩潰VS 2008

我明白我可以設置通過使用下面的代碼安全上的控制線程的文字:

private delegate void SetTextD(Control control, string value); 

private static void SetText(Control control, string value) 
{ 
    if(control.InvokeRequired) 
    { 
     control.Invoke(new SetTextD(SetText), new object[] {control, value}); 
    } 
    else 
    { 
     control.Text = value; 
    } 
} 

然後在我的表單代碼我可以打電話:

SetText(lblStatus, "Updating..."); 

我的目標是創建自定義控件,繼承Label。那麼這個類裏面,在Text屬性我可以叫:

lblStatus.Text =「更新...」

然後,它會自動地做正確的線程安全的代碼。

下面是我在我的類代碼:

public class ThreadSafeLabel : Label 
{ 
    private delegate string GetTextD(); 
    private delegate void SetTextD(string value); 

    private string GetText() 
    { 
     if (InvokeRequired) 
     { 
      return (string)Invoke(new GetTextD(GetText)); 
     } 
     return Text; 
    } 

    private void SetText(string value) 
    { 
     if(InvokeRequired) 
     { 
      Invoke(new SetTextD(SetText), new object[] {value}); 
     } 
     else 
     { 
      Text = value; 
     } 
    } 

    public override string Text 
    { 
     get 
     { 
      return GetText(); 
     } 
     set 
     { 
      SetText(value); 
     } 
    } 
} 

現在,當我嘗試將此控件添加到我的形式,它崩潰VS 2008年我在想,也許它與做將它添加到表單時設置初始文本屬性,但不確定。

對我可能會做錯什麼或者我可能會錯過什麼想法?

如果不清楚,請詢問。

謝謝!

+1

你會得到什麼例外? – Clyde 2009-07-09 15:02:21

+0

`StackOverflowException`。 – SLaks 2009-07-09 15:20:10

回答

1

由於C#3.0的匿名方法,您不需要單獨設置和獲取方法。做你要找的最簡單的方法是這樣的:

public class ThreadSafeLabel : Label { 
    public override string Text { 
     get { 
      return InvokeRequired ? Invoke(new Func<string>(() => base.Text)) : base.Text; 
     } 
     set { 
      if (InvokeRequired) 
       BeginInvoke(new Action(() => base.Text = value)); 
      else 
       base.Text = value; 
     } 
} 

請注意,我使用BeginInvoke使調用線程不會等待調用完成;您可能需要將其更改爲Invoke

編輯

與您的代碼的問題是,你的set和get方法被再次調用您的重寫Text財產,創造一個infinte循環,導致堆棧過低(例外,而不是網站) 。您需要編寫base.Text以調用基類的Text屬性的實現。

2

嘗試

return base.Text; 

或者你會遇到一個無限循環(當您添加標籤到窗體的文本屬性進行查詢 - 和無限循環,使VS崩潰)。你的二傳手也一樣。