2009-04-22 81 views
14

有沒有在C#中檢查對象是否掛起的方法?我有一個TreeView,我需要知道它是否仍然掛起。檢查掛起佈局

myTreeView.BeginUpdate(); 
myTreeView.SuspendLayout(); 

// Do Stuff. 

myTreeView.EndUpdate(); 
myTreeView.ResumeLayout(); 

因爲我有這個代碼遞歸函數我想知道如果TreeView已被暫停。

+1

目前尚不清楚你的意思是什麼 「暫停」。 – 2009-04-22 14:38:20

+1

我會標記這個來表示你正在使用什麼類庫... WinForms或者WPF。 – 2009-04-22 15:13:08

回答

10

從verminity的答案繼你有一個選項:

使用下面的類,你需要將其掛起

public class SuspendAwareTreeView : TreeView  
{ 
    public readonly T RealControl; 
    private int suspendCount; 

    public bool IsSuspended 
    { 
     get { return suspendCount > 0; } 
    } 

    public Suspendable(T real) { this.RealControl = real; } 

    public void SuspendLayout() 
    { 
     this.suspendCount++; 
     this.RealControl.SuspendLayout(); 
    } 

    public void ResumeLayout() 
    { 
     this.RealControl.ResumeLayout(); 
     this.suspendCount--; 
    } 
} 

然後使用這個類的一切內部。

顯然這不會工作,如果你曾經將類傳遞給僅僅期望控件或者其他控件以外的東西來設置它。

如果這是你將被迫去與各種不到愉快的解決方案的情況下:

  • 寫一個新的用戶控件包裝了TreeView和推遲到它的所有呼叫,但保持暫停狀態。
    • 生成的實例不再是「is-a TreeView」,這會導致問題。
    • 維護工作可能很高。
    • 如果由於某種原因樹視圖決定暫停自己,這將打破。
    • 新版本的運行時不太可能破壞任何東西,你根本無法不費力地獲得新功能。
  • 實現一個全新的TreeViewEx暴露出這種狀態
    • 產生的實例不再「是一個樹視圖」,這將導致問題。
    • 維護工作可能高
    • 也突破不了,因爲你有完全的控制,可以從運行時不會破壞任何原有雖然
    • 新版本的分歧,你根本不會得到沒有顯著努力的新功能(可能違反法律/ EULA)。
  • 破壞封裝
    • 沒有改變FO類型系統,一切繼續工作。
    • 維護工作運行時改變潛在的高
    • 應用將打破,如果他們下的運行時更改

對於您的需求當且僅當你控制這個完全運行在運行時版本(即受控企業環境)以下邪惡但有效的破解是合適的。只要你測試任何時候你升級它可能會繼續努力工作。

public class ControlInvader 
{ 
    private static readonly System.Reflection.FieldInfo layoutSuspendCount = 
     typeof(Control).GetField("layoutSuspendCount", 
      System.Reflection.BindingFlags.Instance | 
      System.Reflection.BindingFlags.NonPublic); 

    private readonly Control control;   

    public bool IsSuspended 
    { 
    get 
    { 
     return 0 != (byte)layoutSuspendCount.GetValue(this.control); 
    } 
    } 

    public Suspendable(Control control) { this.control = control; }  
} 

將此附加到您的TreeView,然後您可以隨時檢查該值。

重申這是脆弱並且完全不適合的環境,其中底層運行時的版本沒有嚴格控制,並且您可以在這裏處理可能的重大努力以解決這個突變問題。 你會很好地包含一個靜態初始化程序,該初始化程序檢查該字段是否實際存在並且是正確的類型,如果不是,則會中止。

3

就讓我們來看看在Reflector在從Control的SuspendLayout方法顯示如下:

public void SuspendLayout() 
{ 
    this.layoutSuspendCount = (byte) (this.layoutSuspendCount + 1); 
    if (this.layoutSuspendCount == 1) 
    { 
     this.OnLayoutSuspended(); 
    } 
} 

因爲它不設置任何公開的標誌,和OnLayoutSuspended()方法是內部無論如何都不知道控制權何時被暫停。

您可以使用新的Suspend和ResumeLayout方法創建樹視圖的子類,但由於基本方法不是虛擬的,因此很難保證它們在所有情況下都會被調用。

+0

爲什麼你不能使用反射來獲得layoutSuspendCount成員? – 2009-04-23 04:21:19

8

好吧,這是一種遲到的回答,但在內部,控制器正在跟蹤計數,並且只會在最簡歷語句中恢復。那麼,爲什麼你在第一時間關心它,你只要確保你叫暫停,並在finally塊恢復它:

void Recursive(Control c) 
{ 
    c.SuspendLayout(); 
    try 
    { 
    if (existCondition) return; 
    // do stuff 
    Recursive(c); 
    } 
    finally 
    { 
    c.ResumeLayout(true); 
    } 
} 

這工作,因爲下面是如何控制內部反應您的通話以下順序:

c.SuspendLayout() // 1st call suspends layout 
c.SuspendLayout() // 2nd and subsequent call only increase the count and does nothing. 
.... 
c.ResumeLayout(true) // this decrease the count to 1 and does NOT actually resumes layout. 
c.ResumeLayout(true) // this set the count to 0 and REALLY resumes layout. 

HTH