之前写了个有关PDF发票信息提取,文件管理的小工具。其中碰到了个小问题:动态生成几组未知数量的控件,访问他们的事件,属性,以及控件之间相互控制。自己写了一套,后来觉得不是很好,但是网上没有查到相关资料,就分享出来吧。
这里打个比方,现在需要导入未知数量的PDF文件,一条PDF文件对应一组控件,假如这组控件有一个Label,多个Button,Label可以用于显示文件路径,Button用于控制Label文件(查看,删除,修改,确定,保存等)。
首先这里使用的是WPF,但是不管是WPF还是WinForm方法是一样的。动态生成控件的方法如下:
private void initialControl(){
//动态生成label,虽然是WPF,但是很Winform属性类似
Label label = new Label();
label.Name = "labelTest";
label.Height = 30;
label.Width = double.NaN;
label.HorizontalAlignment = HorizontalAlignment.Left;
label.VerticalAlignment = VerticalAlignment.Top;
label.Margin = new Thickness(10,10,10,10);
label.Content = dicItem.Value[i - indexMark];
label.Foreground = new SolidColorBrush(Colors.White);
label.Background = new SolidColorBrush(Colors.Transparent);
//这里是关键,过过没有添加到容器中,那么即使你之前声明一个控件也不会显示在窗体上
gridControl.Children.Add(label);
//动态生成Buttn,方法和Label相似
Button btn = new Button();
btn.Name = "btnTest";
btn.Height = 20;
btn.Width = 45;
btn.HorizontalAlignment = HorizontalAlignment.Right;
btn.VerticalAlignment = VerticalAlignment.Top;
label.Margin = new Thickness(10,10,10,10);
btn.Content = "Button";
btn.Foreground = new SolidColorBrush(Colors.Black);
gridControl.Children.Add(btn);
btn.Click += btnModify_Click;
}
我们用OepenFileDialog打开一些文件:
private string[] pdfFileName { get; set; }
private void BtnInput_Click(object sender, RoutedEventArgs e)
{
var openFileDialog = new OpenFileDialog();
openFileDialog.Title = "选择文件";
openFileDialog.Filter = "pdf File|*.pdf";
openFileDialog.FileName = "选择文件夹.";
openFileDialog.Multiselect = true; //允许同时选择多个文件
bool? result = openFileDialog.ShowDialog();
if (result != true)
{
return;
}
else
{
pdfFileName = openFileDialog.FileNames;
}
}
具体思路为,每条pdf文件对应生成一个Label和多个Button,这个Label和Button我们看做一组控件(假定Label用于显示PDF的路径,Button为打开对应路径的PDF文件)那么我们默认有无数个控件组,所以需要一个标识来区分这些控件组,在这可以使用Dictionary<int,List< object>>,Dictionary的key代表标识(第几条PDF),value为一个object类型的List,这个List我们来记控件组。不管是Label还是Button,在我们访问属性的时候都是通过Name(Id)来访问这些控件,在动态生成控件的时候,我们需要使用一些类型来代替控件中的参数:
#region button name define
//定义一些类型来动态添加控件的Name,为了使他们不一致,否则没有办法访问
private string btnModify = "btnModify";
private string btnView = "btnView";
private string btnSave = "btnSave";
private string btnCancel = "btnCancel";
private string labelPath = "labelPath";
#endregion button name define
private void initialControl(){
// pdfFileName.Length获得文件数量
for (int i = 0; i < pdfFileName.Length; i++)
{
//用于存放一组控件,每次存放结束会添加到Dictionary中,for循环每次循环就会new一次
List<object> controlCollection = new List<object>();
//动态生成label
Label label = new Label();
//Name 为"labelPath1""labelPath2""labelPath3"....
label.Name = labelPath + i;
label.Height = 30;
label.Width = double.NaN;
label.HorizontalAlignment = HorizontalAlignment.Left;
label.VerticalAlignment = VerticalAlignment.Top;
//Margin对应参数代表的是左上右下,所以唯一需要控制上参数
label.Margin = new Thickness(60, i * 30 + 10, 0, 0);
label.Content = dicItem.Value[i - indexMark];
label.Foreground = new SolidColorBrush(Colors.White);
label.Background = new SolidColorBrush(Colors.Transparent);
gridControl.Children.Add(label);
//将label添加到控件组
controlCollection.Add(label);
//动态生成buttn1
Button btn = new Button();
btn.Name = btnModify + i;
btn.Height = 20;
btn.Width = 45;
btn.HorizontalAlignment = HorizontalAlignment.Right;
btn.VerticalAlignment = VerticalAlignment.Top;
btn.Margin = new Thickness(0, i * 30 + 11, 180, 0);
btn.Content = "移动";
btn.Foreground = new SolidColorBrush(Colors.Black);
gridControl.Children.Add(btn);
btn.Click += btnModify_Click;
//将button添加到控件组
controlCollection.Add(btn);
//将一组控件添加到dictionary中并打上index
dicControl.Add(i, controlCollection);
}
}
存放控件组的Dictionary是这个样子的:
List每个List都存放着一个Label和一个Button,Name格式都为XXX+index
接下来就是怎么通过点击button来响应同组的Label或者Button:
private void btnModify_Click(object sender, RoutedEventArgs e)
{
//这里通过sender拿到button的name,通过替换到定义的模板拿到index
var btnIndex = (sender as Button).Name.Replace(btnModify, "");
//通过index拿到对应的Button,强转下就可以修改Button的属性了
//在这个实例中List[0]代表Label List[1]代表Button
(dicControl[int.Parse(btnIndex)][1] as Button).Visibility = Visibility.Visible;
}