为 WinForms 控件恢复 FlowLayout






3.45/5 (10投票s)
2004年10月8日
1分钟阅读

120419

1409
本文档描述了如何创建一个允许 WinForms 使用 FlowLayout 定位的 Panel。

引言
由于下一个 Visual Studio 处于 Beta 2 阶段,并且 FlowLayout 预计会在该版本中回归,这可能为时已晚,但我觉得有必要分享一下。FlowLayout 选项在 .NET WinForms 中已经缺失了一段时间。虽然我们中的许多人并不介意绝对定位,但当您想动态添加控件但又不想担心 System.Drawing.Points 或 .Top 和 .Left 属性时,它可能会变得很麻烦(或者至少令人恼火)。
背景
我目前正在实现一个缩略图视图,并且对 WinForms 中没有 FlowLayout 选项感到苦恼。在 Google 上搜索 FlowLayout 控件后,发现相关的控件非常稀少,所以我决定自己编写一个并分享给大众使用。
自从我发布这篇文章以来,我对它进行了一些增强,包括添加了一个 LayoutStyle 属性,该属性接受一个 enum,用于 LayoutStyles.FlowLayout 或 LayoutStyles.GridLayout。
用法
FlowLayoutPanel 是一个小型应用程序,其中包含一个自定义控件(FlowLayoutPanel.cs),它扩展了 System.Windows.Forms.Panel 并重写了
protected override void OnLayout(LayoutEventArgs levent)
以处理 Panel 的 FlowLayout 行为。
它简单直接,所有实际工作都在上面的方法中完成(代码如下)。下载包含一个来自 Visual Studio .NET 2003 的解决方案,该解决方案捆绑了一个示例应用程序和 FlowLayoutPanel。除了添加 LayoutStyle 属性之外,它与标准 Panel 的用法没有显著差异,当然,如果将 LayoutStyle 属性设置为 LayoutStyles.FlowLayout,则通过 this.Controls.Add(someControl) 或在设计模式下拖放控件,将自动使用 FlowLayout 特性对控件进行定位。
protected override void OnLayout(LayoutEventArgs levent)
{
    if (this.LayoutStyle == LayoutStyles.FlowLayout) 
    {
      int nextTop = 0, nextLeft = 0;
      int maxHeight = 0, maxWidth = 0;
      int ParentWidth;
      if (this.Parent != null)
      {
          ParentWidth = this.Parent.Width;
      }
      else
      {
          ParentWidth = this.Width;
      }
      foreach(Control myControl in this.Controls)
      {
          myControl.Top = nextTop;
          myControl.Left = nextLeft;
          if (myControl.Height > maxHeight)
          {
              maxHeight = myControl.Height;
          }
          if (myControl.Width > maxWidth)
          {
              maxWidth = myControl.Width;
          }
          if ((nextLeft + myControl.Width + maxWidth) >= ParentWidth)
          {
              nextTop += maxHeight;
              nextLeft = 0;
          }
          else
          {
              nextLeft += myControl.Width;
          }
      } 
    this.AutoScrollPosition = new System.Drawing.Point(0,0);
    base.OnLayout (levent);
}