windows 检查挂起布局

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/777467/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 12:20:26  来源:igfitidea点击:

Check SuspendLayout

c#.netwindowswinforms

提问by norlando

Is there a way in C# to check if an object is suspend? I have a TreeView that I need to know if it is still suspend.

C# 中有没有办法检查对象是否挂起?我有一个 TreeView,我需要知道它是否仍处于挂起状态。

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

 // Do Stuff.

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

Because i have this code in a recursive function I want to know if the TreeView is already been suspended.

因为我在递归函数中有这段代码,所以我想知道 TreeView 是否已经被挂起。

采纳答案by ShuggyCoUk

Following on from verminity's answer you do have one option:

继 verminity 的回答之后,您确实有一个选择:

Use the following class

使用以下类

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--;
    }
}

Then use this class for everything internally where you need to suspend it.

然后将此类用于内部需要暂停的所有内容。

Obviously this won't work if you ever pass the class around to something that only expects a control or if something else outside your control sets it.

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

If this is the case you would be forced to go with a variety of less than pleasant solutions:

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

  • Write a new User control which wraps the TreeView and defers all calls to it but maintains the suspended state.
    • the resulting instance is no longer "is-a TreeView" which will cause problems.
    • maintenance effort possibly high.
    • if for some reason the treeview ever decided to suspend itself this will break.
    • new version of the runtime unlikely to break anything, you simply won't gain new functionality without effort.
  • Implement an entirely new TreeViewEx which exposes this state
    • the resulting instance is no longer "is-a TreeView" which will cause problems.
    • maintenance effort possibly high
    • can never break since you have total control, can diverge from original though
    • new version of the runtime unlikely to break anything, you simply won't gain new functionality without significant effort (possibly in violation of the law/EULA).
  • Violate Encapsulation
    • No alteration fo the type system, everything else continues to work.
    • Maintenance effort potentially high on runtime change
    • apps will break if the runtime changes underneath them
  • 编写一个新的 User 控件,它包装 TreeView 并推迟对它的所有调用,但保持挂起状态。
    • 结果实例不再是“is-a TreeView”,这会导致问题。
    • 维护工作量可能很高。
    • 如果由于某种原因树视图决定暂停自己,这将中断。
    • 新版本的运行时不太可能破坏任何东西,您根本不会不费吹灰之力就获得新功能。
  • 实现一个全新的 TreeViewEx 来暴露这个状态
    • 结果实例不再是“is-a TreeView”,这会导致问题。
    • 维护工作量可能很高
    • 永远不会中断,因为您拥有完全控制权,但可以与原始版本不同
    • 新版本的运行时不太可能破坏任何内容,如果不付出大量努力(可能违反法律/EULA),您将无法获得新功能。
  • 违反封装
    • 没有改变类型系统,其他一切继续工作。
    • 运行时更改可能导致维护工作量很大
    • 如果运行时在它们下面发生变化,应用程序将中断

For your needs if and only ifyou control the runtime versions this operates on entirely (i.e. a controlled corporate environment) the following evilbut effective hack is appropriate. So long as you test any time you upgrade it may well keep working with little effort.

对于您的需求,当且仅当您完全控制运行时版本(即受控的公司环境)时,以下邪恶但有效的 hack 是合适的。只要您在升级时进行测试,它就可以毫不费力地继续工作。

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; }     
}

Attach this to your TreeView and then you can inspect the value whenever you like.

将此附加到您的 TreeView,然后您可以随时检查该值。

To reiterate this is fragileand entirely inappropriate for an environment where the version of the underlying runtime is not strictly controlled and where you can handle possible significant efforts to fix this on a breaking change. You would do well to include a static initializer which checks if the field actually existed and was the right type and aborted if not.

重申这是脆弱的,完全不适合底层运行时的版本没有受到严格控制的环境,并且您可以处理可能的重大努力以在重大更改时修复此问题。您最好包含一个静态初始值设定项,用于检查该字段是否确实存在以及是否为正确类型,如果不正确则中止。

回答by Kenneth Xu

Well, it's kind of late answer, but internally, the control is tracking the count and will only resume in the out most resume statement. So why do you care about it in the first place, you just make sure that you call the suspend and resume it in finally block:

嗯,这是一种迟到的答案,但在内部,控件正在跟踪计数并且只会在最外面的 resume 语句中恢复。那么你为什么首先关心它,你只需确保你调用了挂起并在 finally 块中恢复它:

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

This works because below is how Control internally reacts to your call in below order:

这是有效的,因为以下是 Control 内部如何按以下顺序对您的呼叫做出反应:

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

HTH

回答by Martin Harris

A quick look in Reflectorat the SuspendLayout method from System.Windows.Forms.Control shows the following:

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

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

Since it doesn't set any public flags, and the OnLayoutSuspended() method is internal there doesn't appear to be anyway to find out when the control is suspended.

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

You could create a subclass of the treeview with new Suspend and ResumeLayout methods, but it would be difficult to guarantee that they would be called in all circumstances since the base methods are not virtual.

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