检查SuspendLayout

nor*_*ndo 16 .net c# windows winforms

在C#中是否有办法检查对象是否挂起?我有一个TreeView,我需要知道它是否仍然挂起.

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

 // Do Stuff.

 myTreeView.EndUpdate();
 myTreeView.ResumeLayout();
Run Code Online (Sandbox Code Playgroud)

因为我在递归函数中有这个代码,我想知道TreeView是否已被挂起.

Shu*_*oUk 11

根据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--;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在需要暂停它的内部使用此类.

显然,如果您将类传递给只需要控件或者控制之外的其他东西设置它,那么这将不起作用.

如果是这种情况,您将被迫使用各种不太令人满意的解决方案:

  • 编写一个新的User控件,它包装TreeView并推迟对它的所有调用,但保持挂起状态.
    • 生成的实例不再是"is-a TreeView",它会导致问题.
    • 维护工作量可能很高.
    • 如果由于某种原因树视图决定暂停,这将打破.
    • 新版本的运行时不太可能破坏任何东西,你根本就不会毫不费力地获得新的功能.
  • 实现一个全新的TreeViewEx,它暴露了这种状态
    • 生成的实例不再是"is-a TreeView",它会导致问题.
    • 维护工作量可能很高
    • 因为你有完全的控制权,所以可以永远不会破裂
    • 新版本的运行时不太可能破坏任何东西,如果没有很大的努力(可能违反法律/ EULA),您将无法获得新的功能.
  • 违反封装
    • 类型系统没有改变,其他一切继续工作.
    • 维护工作可能会对运行时更改造成很
    • 如果运行时在其下面发生变化,应用程序将会中断

为了您的需求,当且仅当你控制这个完全运行在运行时版本(即控制企业环境中)以下的邪恶而有效的手段是适当的.只要您在升级时进行测试,就可以轻松地继续工作.

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; }     
}
Run Code Online (Sandbox Code Playgroud)

将其附加到TreeView,然后您可以随时检查值.

重申这一点很脆弱,并且完全不适用于底层运行时版本未受到严格控制的环境,以及您可以在可能的重大工作中解决这一问题.你最好包括一个静态初始化程序,它检查字段是否确实存在并且是正确的类型,如果没有则中止.


Ken*_* Xu 9

好吧,这是一种迟到的答案,但在内部,控件正在跟踪计数,并且只会在大多数简历声明中恢复.那你为什么一开始就关心它,你只需要确保你调用暂停并在finally块中恢复它:

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

这是有效的,因为以下是控制内部如何按以下顺序对您的通话作出反应:

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.
Run Code Online (Sandbox Code Playgroud)

HTH


Mar*_*ris 5

Reflector中快速查看System.Windows.Forms.Control 中的 SuspendLayout 方法显示以下内容:

public void SuspendLayout()
{
    this.layoutSuspendCount = (byte) (this.layoutSuspendCount + 1);
    if (this.layoutSuspendCount == 1)
    {
        this.OnLayoutSuspended();
    }
}
Run Code Online (Sandbox Code Playgroud)

由于它没有设置任何公共标志,并且 OnLayoutSuspended() 方法是内部的,因此似乎无法确定控件何时挂起。

您可以使用新的 Suspend 和 ResumeLayout 方法创建树视图的子类,但很难保证在所有情况下都会调用它们,因为基本方法不是虚拟的。

  • 你可以,ShuggyCoUk 非常完整的答案包括它的代码。但是,不能保证私有字段仍然存在于框架的不同版本中,因此它会给您留下脆弱的代码。 (2认同)