字段列表控件
用于文档编码或质量控制 (QC) 应用程序的编码控件。
引言
我开始编写一个大型程序,其中将包含一些好的功能,以便能够对文档的字段进行编码,并通过搜索字段和/或文档的 OCR 文本轻松检索它们。 我的应用程序的前两个步骤已经完成。 我想分享我编写的一个组件,称为“字段列表”控件。
此控件运行于一个扩展名为 "lst" 的文件,该文件以文本格式携带一个非常简单的结构。
更新
由于其复杂性(!),我只上传了控件示例项目,而不是我正在处理的项目,其中包含该控件。 借助新的示例代码和新的视频剪辑,应该很容易理解此控件及其设计用途。(在此处观看其视频剪辑)
关注点
我可能应该将我的编码水平从 C# 初学者提高到 C# 初学者/中级 :) 使用此控件,字段条目是无限的。 通过它的“滚动条”,用户可以上下移动。
Components
我将在此处包含一个组件:FieldList 控件。
FieldList
控件有一个垂直滚动条和一个容器,该容器在运行时创建标签、文本框和/或下拉框。 这是人们可能从该控件中学到的一个有用之处:如何在运行时创建控件并从中获取信息。 QnCMain
窗体是主编码器窗体的预览。
代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace FieldList
{
public partial class FieldList : UserControl
{
// Fields
// private int intFieldCount; // Number of fields will be set
private const int BoxHeight = 20; // Height of the Textbox
public FieldList()
{
InitializeComponent();
}
// We get the path of the 'lst' file and the lines
// will be skipped at the top of that file
// There might be some user notes on the top
// that program should skip at streamread
public void LoadFields(string FieldFilePath)
{
// Check the path
if (File.Exists(FieldFilePath) != true)
{
throw new Exception("'Field List' File Can not be found!");
}
string LineData; // Line datab from 'lst' file
string LabelText; // Field label text
string ControlBoxName; // Combobox and textbox names created with this
string[] SplitText; // Splitter
int ControlCount = 0; // This calculates the 'top' for the controls
int ii = 0; // Loop to bypass top lines of the 'lst' file
int SkipFirstLines;
// panel1.Top = 0; // Set container's 'top' value
panel1.Width = (this.Width - 10) - SCRBar.Width;
// Set container's 'width' value
// Open Stream to tread
StreamReader CurrentFields = new StreamReader(FieldFilePath);
// Find out how many lines wil be skipped
SkipFirstLines = Convert.ToInt32(CurrentFields.ReadLine());
// Set fields
for (ii = 0; ii < SkipFirstLines; ii++) // First two lines are not fields
{
LineData = CurrentFields.ReadLine();
}
while (CurrentFields.EndOfStream != true)
{
LineData = CurrentFields.ReadLine();
SplitText = LineData.Split('@');
LabelText = SplitText.GetValue(0).ToString();
ControlBoxName = LabelText.Replace(' ','_');
// Replace spaces with
// underscores for text and combo box names
if (ControlCount > 0)
{
ControlCount = ControlCount + (BoxHeight + 2);
// Encrement 'top' value
}
else
{
ControlCount = 1; // This is set to one only once.
// Code will not come here the second time
}
if (SplitText.Count() > 1)
{
// Drop Down Control
ComboBox NewComboBox = new ComboBox();
NewComboBox.Width = ((panel1.Width / 3) * 2) - 5;
NewComboBox.Height = BoxHeight;
NewComboBox.Left = (panel1.Width / 3) + 5;
NewComboBox.Top = ControlCount;
for (ii = 0; ii < (SplitText.GetUpperBound(0)); ii++)
{
NewComboBox.Items.Add (SplitText.GetValue(ii+1));
}
NewComboBox.Name = "cmb" + ControlBoxName;
panel1.Controls.Add(NewComboBox);
NewComboBox.SelectedIndex = 0;
}
else
{
// Text Control
TextBox NewTextBox = new TextBox();
// Space little less than 2/3
NewTextBox.Width = ((panel1.Width / 3) * 2) - 5;
NewTextBox.Height = BoxHeight;
NewTextBox.Left = (panel1.Width / 3) + 5; // Start next to label
NewTextBox.Top = ControlCount;
NewTextBox.Name = "txt" + ControlBoxName;
panel1.Controls.Add(NewTextBox);
}
CreateLabel(ControlCount, LabelText);
panel1.Height = ControlCount + 32;
}
ScrollSet();
CurrentFields.Dispose();
}
private void CreateLabel(int TopValue, string LabelName)
{
// Label Control
Label NewLabel = new Label();
NewLabel.Width = (panel1.Width / 3) + 5; // Space little less than 2/3
NewLabel.Height = BoxHeight;
NewLabel.Left = 0; // Start at the left edge of the panel1
NewLabel.Top = TopValue;
panel1.Controls.Add(NewLabel);
NewLabel.TextAlign = ContentAlignment.MiddleRight;
NewLabel.Text = LabelName;
}
private void SCRBar_Scroll(object sender, ScrollEventArgs e)
{
panel1.Top = -SCRBar.Value;
}
private void FieldList_SizeChanged(object sender, EventArgs e)
{
ScrollSet();
}
private void ScrollSet()
{
if (panel1.Height > this.Height)
{
SCRBar.Enabled = true;
SCRBar.Maximum = panel1.Height - this.Height;
}
else
{
SCRBar.Enabled = false;
}
panel1.Top = 0; // Set container's 'top' value
}
public List<string> GetValues()
{
List<string> strValues = new List<string>();
foreach (Control BoxControlText in panel1.Controls)
{
if (BoxControlText is TextBox || BoxControlText is ComboBox)
{
strValues.Add(BoxControlText.Text);
}
}
return strValues;
}
public void SetValues(List<string> BoxValues)
{
int ii = 0;
foreach (Control BoxControlText in panel1.Controls)
{
if (BoxControlText is TextBox || BoxControlText is ComboBox)
{
BoxControlText.Text = BoxValues[ii];
ii++;
}
}
}
}
}
以上代码是该控件的完整代码。 我确信可以用更简单的方法来完成,但代码完全实现了我的需求。 如果您能为它提出一些更快捷的方法,请告诉我。
File.Exists(FieldFilePath)
当涉及到检查文件或文件夹时,这是我在编码方面最好的朋友之一。
panel1.Width = (this.Width - 10) - SCRBar.Width;
有时我在运行时设置某些控件的宽度。 这是一个很好的做法,可以使应用程序中的事物更有条理。
for (ii = 0; ii < SkipFirstLines; ii++)
这是我们跳过前几行之后的代码(可选)。 我决定在 Field List 文件中包含标题行的原因是放入一些提醒或警告。 有时人们会打开文本文件并对其进行修改,让他们知道不要碰其中的某些内容是件好事。
ControlCount = ControlCount + (BoxHeight + 2);
此行是计算容器高度的主要行。 它还设置了下一个控件(标签、文本框和/或组合框)将从顶部(容器顶部)开始的位置。
ControlBoxName = LabelText.Replace(' ','_');
当我命名控件时,我确保单词之间没有空格。 我还会在名称的开头添加 "cbo" 和/或 "txt" 以便轻松识别控件的类型。
panel1.Controls.Add(NewTextBox);
每个控件都有一个“Add
”方法,所以我们所要做的就是将控件添加到我们想要的位置……在这种情况下,添加到容器控件中。 以防万一你问,“为什么放入容器?” 我使用容器将所有内容分组,如果项目多于控件本身可以容纳的,则实际上用滚动条上下移动它(检查 private void ScrollSet()
方法)。
我在该代码中大量使用了 List<string>
。 我还使用 "@" 作为下拉菜单项目的分隔符,并使用一个“隐藏的列表框”来保存设置期间的“标题文本”。 请记住,这些事情可以用多种方式完成。 您不必使用分隔符,您可以使用其他方法,例如行,或者使用数据库来保存您的下拉信息和其他字段信息。 您可以编写自己的数组类等,而不是使用“隐藏的列表框”。 我采取了捷径,使用了我可用的工具,而不是编写更多的代码行。 来自 VB 世界的习惯。 专业人士会对这段代码翻白眼……我想知道他们会怎么做 :)