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
{
private const int BoxHeight = 20;
public FieldList()
{
InitializeComponent();
}
public void LoadFields(string FieldFilePath)
{
if (File.Exists(FieldFilePath) != true)
{
throw new Exception("'Field List' File Can not be found!");
}
string LineData; string LabelText; string ControlBoxName; string[] SplitText; int ControlCount = 0; int ii = 0; int SkipFirstLines;
panel1.Width = (this.Width - 10) - SCRBar.Width;
StreamReader CurrentFields = new StreamReader(FieldFilePath);
SkipFirstLines = Convert.ToInt32(CurrentFields.ReadLine());
for (ii = 0; ii < SkipFirstLines; ii++) {
LineData = CurrentFields.ReadLine();
}
while (CurrentFields.EndOfStream != true)
{
LineData = CurrentFields.ReadLine();
SplitText = LineData.Split('@');
LabelText = SplitText.GetValue(0).ToString();
ControlBoxName = LabelText.Replace(' ','_');
if (ControlCount > 0)
{
ControlCount = ControlCount + (BoxHeight + 2);
}
else
{
ControlCount = 1; }
if (SplitText.Count() > 1)
{
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
{
TextBox NewTextBox = new TextBox();
NewTextBox.Width = ((panel1.Width / 3) * 2) - 5;
NewTextBox.Height = BoxHeight;
NewTextBox.Left = (panel1.Width / 3) + 5; 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 NewLabel = new Label();
NewLabel.Width = (panel1.Width / 3) + 5; NewLabel.Height = BoxHeight;
NewLabel.Left = 0; 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; }
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 :)