我们的生活中存在着大量的容器关系,比如吃饭需要有碗装米饭,碗放在桌上,桌在家里,家在某一栋楼内,楼在小区内...。一层一层的,控件开发也是这样。在上一篇中,我们介绍了一个简单的控件是如何编写的,本章再说说怎样实现多级的控件。
说到这里,我们需要一个例子,ACDSEE有个展现目录下所有文件夹和图片的控件,如下图。我们将一步步对该控件的开发过程进行详解。
第一步,我们新建一个用户控件,假设名称为ImageBox,为类加上声明语句:
public partial class ImageBox : UserControl
{
//.....
这样,ImageBox就为定义为容器控件,它可以摆放其他控件在容器控件里面。
第二部,我们再新建一个用户控件,就是每个显示图片的子项了,名称为ImageItem,并在设计器中设计它!
第三步,容器里面的项,和ListView的ListViewItem一样,里面有一个ItemList的集合,我们也需要实现这样的结合,并且希望可以使用[int]来获得Box里面的项,要实现集合的结构,我们需要使用System.Collections.ICollection接口,
{
private SortedList items = new SortedList();
public int Count
{
get
{
return items.Count;
}
}
//------------------------------------事件----------------------------------------
public delegate void itemDelegate(ImageItem itemIsAdd,int addIndex);
public event itemDelegate AddItem;
//------------------------------------属性----------------------------------------
public ImageItem this[int index]
{
get
{
object tmp = items.GetByIndex(index);
return (ImageItem)tmp;
}
}
public ImageItem this[string name]
{
get
{
object tmp = items[name];
return (ImageItem)tmp;
}
}
//------------------------------------方法----------------------------------------
public void RemoveAll()
{
this.RemoveAllItem();
items.Clear();
}
/// <summary>
/// 添加一个新的图片项
/// </summary>
/// <param name="itemIsAdd">要添加的图片项</param>
/// <returns>包括新增后的图片项数</returns>
public int Add(ImageItem itemIsAdd)
{
if (itemIsAdd.Name == "ImageItem")
{
string autoName = "ImageItemAuto" + getAddItemNum();
itemIsAdd.Name = autoName;
}
if (this.AddItem != null)
{
this.AddItem(itemIsAdd, items.Count + 1);
}
this.items.Add(itemIsAdd.Name, itemIsAdd);
return items.Count - 1;
}
/// <summary>
/// 移除某个图片项
/// </summary>
/// <param name="itemIsRemove">要移除的项</param>
/// <returns>包括新增后的图片项数</returns>
public int Remove(ImageItem itemIsRemove)
{
if(!items.Contains(itemIsRemove.Name))
{
throw new Exception("该图片项不在图片容器中");
}
items.Remove(itemIsRemove.Name);
if (this.RemoveItem != null)
{
this.RemoveItem(itemIsRemove);
}
return items.Count - 1;
}
private int addItemNum = 0;
private string getAddItemNum()
{
addItemNum = addItemNum + 1;
return addItemNum.ToString();
}
#endregion
}
}
第四步,我们需要把集合,容器,子项目这三个东西组装在一起,就完成了我们的图片展现控件了。我们在ImageBox类中加入下面的代码:
private void ImageView_Load( object sender, EventArgs e)
{
Items.AddItem += new ImageItemCollection.itemDelegate(Items_AddItem);
}
private void Items_AddItem(ImageItem itemIsAdd, int itemIndex)
{
itemIsAdd.Size = itemSize;
this.Controls.Add(itemIsAdd);
this.setImageLocation(itemIsAdd, itemIndex);
}
private void setImageLocation(ImageItem itemIsAdd, int itemIndex)
{
int columnNum = this.calculationsColumn();
int imageItemX = 0;
if (itemIndex % columnNum != 0)
{
imageItemX = ((itemIndex % columnNum) - 1) * (itemSize.Width + ImageLayout) + ImageLayout;
}
else
{
imageItemX = (columnNum - 1) * (itemSize.Width + ImageLayout) + ImageLayout;
}
int rowNum = (itemIndex - 1) / columnNum;
int imageItemY = rowNum * (itemSize.Height + ImageLayout) + ImageLayout;
//itemIsAdd.Location = new Point(imageItemX, imageItemY);
itemIsAdd.Left = imageItemX;
itemIsAdd.Top = imageItemY + this.lbl_Point.Top;
}
private int calculationsColumn()
{
int thisWidth = this.Size.Width;
int itemWidth = itemSize.Width + ImageLayout;
int columnNum = thisWidth / itemWidth;
return columnNum;
}
但调用项集合类的Add的时候,会在Box发生Add时间,把新项添加到Box中,并且根据需要,设置图片被插入的位置。如果还有其他的需要,如remove,设置item的大小,定义子项的双击事件等等,读者可以根据本章和上一章的原理,对控件进行扩展。