WinForm 简单实现仿WPF的WrapPanel和StackPanel
public interface IDesiredPanel
{
Size GetDesiredSize(int availableWidth, int avaiableHeight);
}
public class StackPanel : Panel, IDesiredPanel
{
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
List<Control> visibleCtrls = this.GetVisiableControls();
int renderHeight = 0;
for (int i = 0; i < visibleCtrls.Count; i++)
{
Control childCtrl = visibleCtrls[i];
IDesiredPanel idesiredPnl = childCtrl as IDesiredPanel;
Size childDesignSize = (idesiredPnl == null)
? new Size(childCtrl.Width, childCtrl.Height)
: idesiredPnl.GetDesiredSize(this.Width, this.Height);
childCtrl.Location = new Point(0, renderHeight);
childCtrl.Width = base.Width;
renderHeight += childDesignSize.Height;
}
if (base.Parent is IDesiredPanel)
{
if (visibleCtrls.Count > 0)
{
base.Height = renderHeight;
}
else
{
base.Height = 3;
}
}
else
{
// base.Height = renderHeight;
//this.Invalidate();
//this.PerformLayout();
}
}
// Token: 0x06000086 RID: 134 RVA: 0x0000FA04 File Offset: 0x0000DC04
private List<Control> GetVisiableControls()
{
List<Control> controls = new List<Control>();
foreach (object obj in base.Controls)
{
Control c = (Control)obj;
if (c.Visible)
{
controls.Add(c);
}
}
//controls.Reverse();
return controls;
}
// Token: 0x06000087 RID: 135 RVA: 0x0000FA98 File Offset: 0x0000DC98
public Size GetDesiredSize(int availableWidth, int avaiableHeight)
{
List<Control> visibleCtrls = this.GetVisiableControls();
int desiredHeight = 0;
for (int i = 0; i < visibleCtrls.Count; i++)
{
Control childCtrl = visibleCtrls[i];
IDesiredPanel idesiredPnl = childCtrl as IDesiredPanel;
Size childDesignSize = idesiredPnl == null
? new Size(childCtrl.Width, childCtrl.Height)
: idesiredPnl.GetDesiredSize(availableWidth, avaiableHeight);
desiredHeight += childDesignSize.Height;
}
return new Size(availableWidth, desiredHeight);
}
}
public class WrapPanel : Panel, IDesiredPanel
{
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
List<Control> visibleCtrls = GetVisiableControls();
int renderHeight = 0;
int curLineWidth = 0, curLineMaxHeight = 0;
for (int i = 0; i < visibleCtrls.Count; i++)
{
Control childCtrl = visibleCtrls[i];
IDesiredPanel idesiredPnl = childCtrl as IDesiredPanel;
Size childDesiredSize = idesiredPnl == null
? new Size(childCtrl.Width, childCtrl.Height)
: idesiredPnl.GetDesiredSize(this.Width, this.Height);
if (idesiredPnl != null)
{
childCtrl.Width = childDesiredSize.Width;
childCtrl.Height = childDesiredSize.Height;
}
if (curLineWidth == 0)
{ //第一个元素
childCtrl.Location = new Point(0, renderHeight);
curLineWidth += childDesiredSize.Width;
curLineMaxHeight = Math.Max(curLineMaxHeight, childDesiredSize.Height);
}
else if (curLineWidth + childDesiredSize.Width < this.Width)
{ //非第一个元素,再次元素则宽度累加 不会超出
childCtrl.Location = new Point(curLineWidth, renderHeight);
curLineWidth += childDesiredSize.Width;
curLineMaxHeight = Math.Max(curLineMaxHeight, childDesiredSize.Height);
}
else
{ //非第一个元素,再次元素则宽度累加 会超出,采用换行
renderHeight += curLineMaxHeight;
//换行了
childCtrl.Location = new Point(0, renderHeight);
curLineWidth = childCtrl.Width;
curLineMaxHeight = childCtrl.Height;
}
if (curLineWidth > this.Width)
{ //这个元素溢出了
renderHeight += curLineMaxHeight; //累加上
curLineWidth = 0; //重置为0
curLineMaxHeight = 0; //需要换到下一行
}
}
if (curLineWidth > 0)
{
renderHeight += curLineMaxHeight;
}
if(this.Parent is IDesiredPanel)
{
if(visibleCtrls.Count>0)
{
this.Height = renderHeight;
}
else
{
this.Height = 3;
}
}
else
{
this.Height = Math.Max(3, renderHeight);
}
}
private List<Control> GetVisiableControls()
{
List<Control> controls = new List<Control>();
foreach (Control c in this.Controls)
{
if (c.Visible)
{
controls.Add(c);
}
}
//controls.Reverse();
return controls;
}
public Size GetDesiredSize(int availableWidth,int avaiableHeight)
{
List<Control> visibleCtrls = GetVisiableControls();
int desiredHeight = 0;
int curLineWidth = 0,curLineMaxHeight = 0;
for (int i = 0; i < visibleCtrls.Count; i++)
{
Control childCtrl = visibleCtrls[i];
IDesiredPanel idesiredPnl = childCtrl as IDesiredPanel;
Size childDesiredSize = idesiredPnl == null
? new Size(childCtrl.Width, childCtrl.Height)
: idesiredPnl.GetDesiredSize(availableWidth,avaiableHeight);
if (curLineWidth == 0)
{
curLineWidth += childDesiredSize.Width;
curLineMaxHeight = Math.Max(curLineMaxHeight, childDesiredSize.Height);
}
else if (curLineWidth + childDesiredSize.Width < availableWidth)
{
curLineWidth += childDesiredSize.Width;
curLineMaxHeight = Math.Max(curLineMaxHeight, childDesiredSize.Height);
}
else
{
desiredHeight += curLineMaxHeight;
curLineWidth = childCtrl.Width;
curLineMaxHeight = childCtrl.Height;
}
if (curLineWidth > availableWidth)
{
desiredHeight += curLineMaxHeight;
curLineWidth = 0;
curLineMaxHeight = 0;
}
}
if (curLineWidth > 0)
{
desiredHeight += curLineMaxHeight;
}
return new Size(availableWidth, desiredHeight);
}
}
public class FillLastLinePanel : Panel, IDesiredPanel
{
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
List<Control> visibleCtrls = GetVisiableControls();
Size desiredSize = GetDesiredSize(this.Width, this.Height);
int xOffset = 0;
int maxHeight = 0;
for (int i = 0; i < visibleCtrls.Count; i++)
{
Control childCtrl = visibleCtrls[i];
IDesiredPanel idesiredPnl = childCtrl as IDesiredPanel;
Size childDesignSize = idesiredPnl == null
? new Size(childCtrl.Width, childCtrl.Height)
: idesiredPnl.GetDesiredSize(Math.Max(0, this.Width - xOffset), this.Height);
//childCtrl.Height = desiredSize.Height;
childCtrl.Location = new Point(xOffset, 0);
if (i == visibleCtrls.Count - 1)
{
childCtrl.Width = this.Width - xOffset;
if (idesiredPnl != null)
{
childCtrl.Height = this.Height;
}
}
else if (idesiredPnl != null)
{
childCtrl.Width = childDesignSize.Width;
}
xOffset += childCtrl.Width;
maxHeight = Math.Max(maxHeight, childDesignSize.Height);
}
if(this.Parent is IDesiredPanel)
{
if (visibleCtrls.Count > 0)
{
this.Width = xOffset;
this.Height = maxHeight;
}
else
{
this.Height = 3;
this.Width = 3;
}
}
else if (this.DesignMode == false)
{
this.Width = xOffset;
this.Height = maxHeight;
}
}
private List<Control> GetVisiableControls()
{
List<Control> controls = new List<Control>();
foreach (Control c in this.Controls)
{
if (c.Visible)
{
controls.Add(c);
}
}
//controls.Reverse();
return controls;
}
public Size GetDesiredSize(int availableWidth,int avaiableHeight)
{
List<Control> visibleCtrls = GetVisiableControls();
int maxDesiredHeight = 0;
int totalDesiredWidth = 0;
for (int i = 0; i < visibleCtrls.Count; i++)
{
Control childCtrl = visibleCtrls[i];
IDesiredPanel idesiredPnl = childCtrl as IDesiredPanel;
Size childDesiredSize = idesiredPnl == null
? new Size(childCtrl.Width, childCtrl.Height)
: idesiredPnl.GetDesiredSize(Math.Max(0, availableWidth - totalDesiredWidth), avaiableHeight);
maxDesiredHeight = Math.Max(maxDesiredHeight, childDesiredSize.Height);
totalDesiredWidth += childDesiredSize.Width;
}
return new Size(totalDesiredWidth, maxDesiredHeight);
}
}
以上代码在AutoScroll=true会出现bug
转载保留源出处即可,商业使用请自行鉴别,使用本博客中公开内容做任何违法犯罪于本作者无关