FieldList Control
A coding control for document coding or QCing applications.
Introduction
I started to write a large program that will contain some good functions to be able to code fields for documents and retrieve them easily by searching fields and/or the OCRed body of documents. My first two steps of the application are about done. I would like to share one of the components that I wrote, called the "Field List" control.
This control runs of a file with an "lst" extension which carries a very simple structure in text format.
Update
Because of its complicated nature(!) I have only uploaded the control sample project instead of the project I am working on, which includes the control. With new sample code and the new video clip, it should be easy to understand this control and what it is designed for. (Watch its video clip here)
Points of Interest
I should probably step-up my coding level from C# Beginner to C# Beginner/Intermediate :) With this control, field entries are unlimited. With its "scrollbar", the user can go up and down.
Components
I will include one component here: the FieldList control.
The FieldList
control has a vertical scrollbar and a container that has labels, textboxes, and/or drop-down boxes created during runtime. This is one of the useful things people might learn from this control: how to create controls in runtime and get information from them. The QnCMain
form is the preview of the main coder form.
The Code
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++;
}
}
}
}
}
The above code is the entire code for the control. I am pretty sure this can be done in easier ways, but the code is doing exactly what I need. If you do come up with some more shortcuts for it, please let me know.
File.Exists(FieldFilePath)
This is one of my best friends in coding when it comes to checking a file or a folder.
panel1.Width = (this.Width - 10) - SCRBar.Width;
Sometimes I set the width of some of the controls during runtime. It's a good practice to make things more organized in your application.
for (ii = 0; ii < SkipFirstLines; ii++)
Here is the code after we skip the first few lines (optional). The reason I decided to have header lines in the Field List file is to put some reminders or warnings. Sometimes people open text files and screw around with them, it's a good thing to let them know not to touch some of them.
ControlCount = ControlCount + (BoxHeight + 2);
This line is the main line which the height of the container calculated. It also sets where the next control (label, textbox, and/or combo box) will be located from the top (of the container).
ControlBoxName = LabelText.Replace(' ','_');
When I name the controls, I make sure there are no spaces between words. I also add "cbo" and/or "txt" to the start of the names to easily identify the type of the control.
panel1.Controls.Add(NewTextBox);
Each control has an "Add
" method, so all we have to do is to add the control to wherever we want... in this case, into the container control. Just in case you ask, "Why into the container?" I use the container to group everything, and actually move it up and down with the scrollbar if there are more items than can fit in the control itself (check the private void ScrollSet()
method).
I used List<string>
a lot in this code. I also used "@" as my separator for the dropdownmenu items, and a "hidden listbox" to keep the "header text" during settings. Remember, these things can be done in many ways. You don't have to use separators, you can use other methods such as lines, or use a database to keep your drop down information and other field information. Instead of a "hidden listbox", you can write your own array class etc. I went shortcut, with the tools available for me instead of writing more lines of code. A habit from VB world. Pros will roll their eyes at this code... and I want to know what they would have done :)