Using control arrays in c# .net - c#

I am creating a menu with big buttons containing an image, and text. When selected a border is around the button.
The button text is not always the same, and the result of the button click neither.
I have the image name, and text per button set in a struct like this: (there are four of them, but i'll show 2)
struct ConfigDevSubmenu
{
public const string SubMenuBtnText1 = "";
public const string SubMenuBtnText2 = "text submenu 3 button 1";
public const string SubMenuBtnText3 = "text submenu 3 button 2";
public const string SubMenuBtnText4 = "";
public const string SubMenuBtnImg1 = null;
public const string SubMenuBtnImg2 = "Settings.png";
public const string SubMenuBtnImg3 = "LoadFirmware.png";
public const string SubMenuBtnImg4 = null;
public const string SubMenuBtnBorder1 = "Borderstyle.None";
public const string SubMenuBtnBorder2 = "Borderstyle.FixedSingle";
public const string SubMenuBtnBorder3 = "Borderstyle.FixedSingle";
public const string SubMenuBtnBorder4 = "Borderstyle.None";
}
struct AdvancedSubmenu
{
public const string SubMenuBtnText1 = "text submenu 4 button 1";
public const string SubMenuBtnText2 = "text submenu 4 button 2";
public const string SubMenuBtnText3 = "text submenu 4 button 3";
public const string SubMenuBtnText4 = "text submenu 4 button 4";
public const string SubMenuBtnImg1 = "GenerateEncKey.png";
public const string SubMenuBtnImg2 = "Monitoring.png";
public const string SubMenuBtnImg3 = "AdvancedSettings.png";
public const string SubMenuBtnImg4 = "GenerateConfigFile.png";
public const string SubMenuBtnBorder1 = "Borderstyle.FixedSingle";
public const string SubMenuBtnBorder2 = "Borderstyle.FixedSingle";
public const string SubMenuBtnBorder3 = "Borderstyle.FixedSingle";
public const string SubMenuBtnBorder4 = "Borderstyle.FixedSingle";
}
I do not think this can be done much easier without using database files.
To create the buttons I have this function which has as argument the which struct it should use, and in a switch case structure each button is created.
But I've found myself copy-pasting alot in these functions so this must be possible easier. Therefore I tried something like below, but that does not work. I'd like to know whether it is possible to make that work, and how I should do that.
private void createButtons(string Struct)
{
for (int i = 1; i < 5; i++)
{
SubBtnText[i].Text = Struct.SubMenuBtnText[i];
pictureBoxSubBtn[i].Image = Image.FromFile(Struct.SubMenuBtnImg[i]);
panelSubBtn[i].BorderStyle = Struct.SubMenuBtnBorder[i];
}
}
Any suggetions?

Create a class to hold the button text, image name and border styles - say ButtonData.
Create several lists (or arrays) of ButtonData, one per menu.
You can then iterate over the lists and extract the data.
public class ButtonData
{
public ButtonData(string text, string image, BorderStyle border)
{
Text = text;
Image = image;
Border = border;
}
public string Text { get; private set; }
public string Image { get; private set; }
public BorderStyle Border { get; private set; }
}
var devMenuData = new List<ButtonData> {
new ButtonData("", null, "Borderstyle.None"),
new ButtonData("text submenu 3 button 1",
"Settings.png",
Borderstyle.FixedSingle),
...
};
Your function would something like:
private void CreateButtons(IEnumerable<ButtonData> data)
{
foreach (var buttonData in data)
{
SubBtnText[i].Text = buttonData.Text;
pictureBoxSubBtn[i].Image = Image.FromFile(buttonData.Image);
panelSubBtn[i].BorderStyle = buttonData.Border;
}
}
The above amended function will not work as such, as .NET doesn't have control arrays. You could create another list/array to iterate over or index through for this to work.

reflection
class ButtonParameters
{
public string SubMenuBtnText = string.Empty;
public string SubMenuBtnImg = string.Empty;
public string SubMenuBtnBorder = string.Empty;
}
public Dictionary<int, ButtonParameters> CreateParameters(Type type)
{
FieldInfo[] fieldInfos = type.GetFields(
BindingFlags.Public | BindingFlags.Static);
Dictionary<int, ButtonParameters> parameters = new Dictionary<int, ButtonParameters>();
foreach (FieldInfo fieldInfo in fieldInfos)
{
if (fieldInfo.Name.Contains("SubMenuBtnText"))
{
int index = Convert.ToInt32(fieldInfo.Name.Substring(14));
if (!parameters.ContainsKey(index))
{
parameters.Add(index, new ButtonParameters());
}
parameters[index].SubMenuBtnText = (string)fieldInfo.GetValue(null);
}
else if (fieldInfo.Name.Contains("SubMenuBtnImg"))
{
int index = Convert.ToInt32(fieldInfo.Name.Substring(13));
if (!parameters.ContainsKey(index))
{
parameters.Add(index, new ButtonParameters());
}
parameters[index].SubMenuBtnImg= (string)fieldInfo.GetValue(null);
}
else if (fieldInfo.Name.Contains("SubMenuBtnBorder"))
{
int index = Convert.ToInt32(fieldInfo.Name.Substring(16));
if (!parameters.ContainsKey(index))
{
parameters.Add(index, new ButtonParameters());
}
parameters[index].SubMenuBtnBorder= (string)fieldInfo.GetValue(null);
}
}
return parameters;
}
private void createButtons()
{
Dictionary<int, ButtonParameters> buttons = CreateParameters(typeof(AdvancedSubmenu));
for (int i = 1; i < 5; i++)
{
SubBtnText[i].Text = buttons[i].SubMenuBtnText;
pictureBoxSubBtn[i].Image = Image.FromFile(buttons[i].SubMenuBtnImg);
panelSubBtn[i].BorderStyle = buttons[i].SubMenuBtnBorder;
}
}

Related

How to assign values to multiple form controls?

I have lots of textboxes on a form that I want to fill in with lines I have saved in a text file. I have the text file be read and save every line into an array. Then I want to set each line equal to a corresponding text box.
I currently have it all saved line by line like this:
string[] lines = System.IO.File.ReadAllLines("savedWorkout.txt");
textBox1_1.Text = lines[0];
textBox1_2.Text = lines[1];
textBox1_3.Text = lines[2];
textBox1_4.Text = lines[3];
textBox1_5.Text = lines[4];
textBox1_6.Text = lines[5];
textBox1_7.Text = lines[6];
textBox2_1.Text = lines[7];
textBox2_2.Text = lines[8];
textBox2_3.Text = lines[9];
textBox2_4.Text = lines[10];
textBox2_5.Text = lines[11];
textBox2_6.Text = lines[12];
textBox2_7.Text = lines[13];
I have tried to use a for(i = 0; i < 7, i++) loop, replacing each number in the text box name with i, but I am unsure on how to do this correctly, if possible. Any help would be appreciated.
The textbox names have two numbers. With i being the index in the lines array, the first one can be calculated with
int n1 = i / 7 + 1;
The second one with
int n2 = i % 7 + 1;
Together
for (int i = 0; i < lines.Length; i++) {
int n1 = i / 7 + 1;
int n2 = i % 7 + 1;
Controls[$"textBox{n1}_{n2}"].Text = lines[i];
}
Consider using a DataGridView instead.
See also: Is it possible to bind an array to DataGridView control?.
The following reads lines from a file, dynamically creates a TextBox for each line on to a panel named panel1 were panel1 AutoScroll is set to true so if there are more lines than real estate a scrollbar will be used.
As presented in the screenshot, the width may need to be adjusted to accommodate the text width for the lines.
Place this class into your project
public class TextBoxOperations
{
public static List<TextBox> List { get; set; }
public static int Top { get; set; }
public static int Left { get; set; }
public static int Width { get; set; }
public static int HeightPadding { get; set; }
public static string BaseName { get; set; }
public static Control ParentControl { get; set; }
private static int _index = 1;
public static void Initialize(Control pControl, int pTop, int pBaseHeightPadding, int pLeft, int pWidth)
{
ParentControl = pControl;
Top = pTop;
HeightPadding = pBaseHeightPadding;
Left = pLeft;
Width = pWidth;
List = new List<TextBox>();
}
private static void Create(string text)
{
var button = new TextBox()
{
Name = $"{BaseName}{_index}",
Text = text,
Width = Width,
Location = new Point(Left, Top),
Parent = ParentControl,
Visible = true,
Tag = _index
};
List.Add(button);
ParentControl.Controls.Add(button);
Top += HeightPadding;
_index += 1;
}
public static void Build(string[] lines)
{
foreach (var line in lines)
{
Create(line);
}
}
public static void Save(string fileName)
{
File.WriteAllLines(fileName, List.Select(tb => tb.Text).ToArray());
}
}
Form code with a panel and two buttons, first button loads lines, second provides a method to save the lines to the same file.
public partial class Form1 : Form
{
private readonly string _fileName = "savedWorkout.txt";
public Form1()
{
InitializeComponent();
panel1.AutoScroll = true;
}
private void RunSampleButton_Click(object sender, EventArgs e)
{
var lines = File.ReadAllLines(_fileName);
TextBoxOperations.BaseName = "LineTextBox";
TextBoxOperations.Initialize(panel1, 20, 30, 10, 400);
TextBoxOperations.Build(lines);
}
private void SaveButton_Click(object sender, EventArgs e)
{
TextBoxOperations.Save(_fileName);
}
}

how to append to a c# list from form controls

I have a form with several text boxes. I want to use the input in the text boxes to append to a list in c# which I then want to show in a datagrid as the enteries are entered. But I have an issue. I add the data to the textboxes hit the display to datagrid button I have created and it seems ever time instead of appending items to the list the list is recreated. What am I doing wrong?
'''
{
public LotScan()
{
InitializeComponent();
}
public class LotData
{
public string Lot;
public string Description { get; set; }
public int PO { get; set; }
public string MfgPart { get; set; }
}
// code to add from control data to list
private List<LotData> LoadCollectionData()
{
List<LotData> lot = new List<LotData>();
lot.Add(new LotData()
{
Lot = LotNo.Text,
Description = frmDescription.Text,
PO = int.Parse(frmPO.Text),
MfgPart = frmMfgPart.Text,
});
return lot;
}
//button to add list data to datagrid on form
private void Button_Click(object sender, RoutedEventArgs e)
{
gridLotData.ItemsSource = LoadCollectionData();
LotNo.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmDescription.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmPO.Text = string.Empty;
}
'''
Move this variable to be a private Member variable (just put it a line above the classes constructor method):
List<LotData> lot = new List<LotData>();
public LotScan()
{
InitializeComponent();
gridLotData.ItemsSource = LotDataList;
}
private LotData LoadCollectionData()
{
return new LotData()
{
Lot = LotNo.Text,
Description = frmDescription.Text,
PO = int.Parse(frmPO.Text),
MfgPart = frmMfgPart.Text,
};
}
public class LotData
{
public string Lot;
public string Description { get; set; }
public int PO { get; set; }
public string MfgPart { get; set; }
}
public ObservableCollection<LotData> LotDataList = new ObservableCollection<LotData>();
private void Button_Click(object sender, RoutedEventArgs e)
{
LotDataList.Add(LoadCollectionData());
LotNo.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmDescription.Text = String.Empty;
frmMfgPart.Text = string.Empty;
frmPO.Text = string.Empty;
}

How do I return a class array from one WPF window to another window?

In a WPF window called from the MainWindow.xaml.cs I have a class I defined with multiple elements. I create an array of this class type.
In FieldLengths.xaml.cs I have:
public partial class FieldLengths : Window
{
public FieldJustifyFill[] fjfFields = new FieldJustifyFill[0];
public class FieldJustifyFill
{
public int ColumnNumber { get; set; }
public bool RightJustify { get; set; }
public bool LeftJustify { get; set; }
public bool LeftZeroFill { get; set; }
public bool RightZeroFill { get; set; }
}
I load is this way:
try
{
dtFields = ((DataView)dtGrid.ItemsSource).ToTable();
intNumFields = 0;
for (int intRowCnt = 0; intRowCnt < dtFields.Rows.Count; intRowCnt++)
{
bool blnJustifyRight = Convert.ToBoolean(dtFields.Rows[intRowCnt][2]);
bool blnJustifyLeft = Convert.ToBoolean(dtFields.Rows[intRowCnt][3]);
bool blnLeftZeroFill = Convert.ToBoolean(dtFields.Rows[intRowCnt][4]);
bool blnRightZeroFill = Convert.ToBoolean(dtFields.Rows[intRowCnt][5]);
if (blnJustifyRight || blnJustifyLeft || blnLeftZeroFill || blnRightZeroFill)
{
Array.Resize(ref fjfFields, intNumFields + 1);
fjfFields[intNumFields] = new FieldJustifyFill
{
ColumnNumber = intRowCnt,
RightJustify = blnJustifyRight,
LeftJustify = blnJustifyLeft,
LeftZeroFill = blnLeftZeroFill,
RightZeroFill = blnRightZeroFill
};
intNumFields += 1;
}
}
}
catch (Exception ex)
{
string strMsg;
strMsg = "RefreshRowSize, error '" + ex.Message + "' has occurred.";
System.Windows.MessageBox.Show(strMsg);
}
In MainWindow.xaml.cs I have this:
public partial class MainWindow : Window
{
FieldJustifyFillDest[] fjfFieldsDest = new FieldJustifyFillDest[0];
And in a routine I try to get the values from FixedLengths.xaml.cs like this:
FieldLengths flWin = new FieldLengths(strInputName, strFieldInfo, null, null, null, strMappingMetadata);
flWin.Left = System.Windows.Application.Current.MainWindow.Left + 15;
flWin.Top = desktopWorkArea.Top + 25;
flWin.ShowDialog();
if (flWin.blnFLCreateFile)
{
string strPrgFileName;
Array.Resize(ref fjfFieldsDest, flWin.fjfFields.Length);
for (int i = 0; i < flWin.fjfFields.Length; i++)
{
int intColumnNumber = flWin.fjfFields[i].ColumnNumber;
bool blnRightJustify = flWin.fjfFields[i].RightJustify;
bool blnLeftJustify = flWin.fjfFields[i].LeftJustify;
bool blnLeftZeroFill = flWin.fjfFields[i].LeftZeroFill;
bool blnRightZeroFill = flWin.fjfFields[i].RightZeroFill;
fjfFieldsDest[i] = new FieldJustifyFillDest
{
ColumnNumber = intColumnNumber,
RightJustify = blnRightJustify,
LeftJustify = blnLeftJustify,
LeftZeroFill = blnLeftZeroFill,
RightZeroFill = blnRightZeroFill
};
}
The variable intColumnNumber, blnRightJustify, blnLeftJustify, blnLeftZeroFill, blnRightZeroFill have the correct values but when it is loaded into fjfFieldsDest[i] they are not correct.
How do I return the class array correctly? I can not find a good example anywhere.
My apologies, my code is working correctly as coded. The debugger reordered the class elements alphabetically and I did not notice. Sorry all. However if the way I am coding it is not correct I welcome any feedback to code correctly.

Variable declaration in the loop using Json

Here is my code in the controller.
public JsonResult directory()
{
List<string> alp = new List<string>();
var alp1 = new List<directories>();
string array = "";
int a = 0;
for (a = 0; a <= 25; a++)
{
int unicode = a + 65;
char character = (char)unicode;
string text1 = character.ToString();
string url1 = "<a href='/Directories/?search=" + text1 + "' 'rel=" + text1 + "'>";
string alpha = text1;
alp.Add(url1);
alphatxt.Add(alpha);
}
var alphaa = alp1.Add(new directories { arrary = url1, character = alphatxt });
return Json(alphaa, JsonRequestBehavior.AllowGet);
}
public class directories
{
public int a { get; set; }
public int unicode { get; set; }
public char character { get; set; }
public string[] arrary { get; set; }
}
Outputs are getting by
alp.Add(url1);
alp.Add(alpha);
How can i call these two outputs outside the loop.
so that i will get my output through the return
Json(alphaa, JsonRequestBehavior.AllowGet);
But I dont know how to declare the output to the variable outside the loop.
If you are trying to build a list of urls, one for each letter, then you can simply do something like:
public List<Directory> GetDirectories()
{
var dirs = new List<Directory>();
for (var ch = 'A'; ch <= 'Z'; ch++)
{
var url = string.Format(
"<a href='/Directories/?search={0}' rel='{0}'>", ch);
dirs.Add(new Directory() { Character = ch, Url = url });
}
return dirs;
}
// Directory class is simplifed a bit in this example
public class Directory
{
public char Character { get; set; }
public string Url { get; set; }
}
And then simply convert it to JSON in a separate method:
public JsonResult directory()
{
var dirs = GetDirectories();
return Json(dirs, JsonRequestBehavior.AllowGet);
}
Using LINQ, it could be simplified to:
private static readonly string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public List<Directory> GetDirectories()
{
return Alphabet
.Select(ch => new Directory() { Character = ch, Url = CreateUrl(ch) })
.ToList();
}
private string CreateUrl(char ch)
{
return string.Format("<a href='/Directories/?search={0}' 'rel={0}'>", ch);
}
The way your code looks right now, it doesn't seem like you need to create this list on the server side at all (you are transferring a bunch of almost equal hard-coded URLs, which can easily be created on the client side using JavaScript), so I presume there is some additional data you are transferring with this query?
You can access the JsonResult.Data property, but I don't really think that is what you need. I suggest to create a method that return the actual result, and inside your action you call that one and serialize it as JSON:
public JsonResult directory()
{
return Json(this.GetDirectories(), JsonRequestBehavior.AllowGet);
}
private List<directories> GetDirectories()
{
... // your original code
}
I tried in many ways, At last got idea to use this way,
Also My code is shown below.
public JsonResult directory()
{
List<string> alp = new List<string>();
var alp1 = new List<directories>();
string array = "";
int a = 0;
for (a = 0; a <= 25; a++)
{
int unicode = a + 65;
char character = (char)unicode;
string text1 = character.ToString();
string url1 = "<a href='/Directories/?search=" + text1 + "' 'rel=" + text1 + "'>";
string alpha = text1;
alp.Add(url1);
alp.Add(alpha);
alp1.Add(new directories { dirurl = url1, text = alpha });
}
return Json(alp1, JsonRequestBehavior.AllowGet);
}
public class directories
{
public string text { get; set; }
public string dirurl { get; set; }
}
}
}

How to implement Action delegate?

I have a class
public class TextBoxConfig
{
public string Caption { get; set; }
public string FieldName { get; set; }
public int Width { get; set; }
public string Name { get; set; }
}
and one other utility class that has a Method that accepts TextBoxConfig as a parameter like this
public class Util
{
public static TextBox ApplySettings(TextBoxConfig config)
{
//Doing something
}
}
In general I can call Util class ApplySettings method like this
TextBoxConfig config = new TextBoxConfig();
config.Caption = "Name";
config.FieldName = "UserName"
config.Width = 20;
config.Name = "txtName";
TextBox txt = Util.ApplySettings(config);
but I want to pass parameter to ApplySettings like this
TextBox txt = Util.ApplySettings(o =>
{
o.Caption = "Name";
o.FieldName = "UserName"
o.Width = 20;
o.Name = "txtName";
});
Please suggest me how can I do it ..
Okay, brace yourself: here is the same thing, just enforced with lambda expressions.
TextBox txt = Util.ApplySettings(o =>
{
o.Caption = "Name";
o.FieldName = "UserName";
o.Width = 20;
o.Name = "txtName";
});
public class Util
{
public static TextBox ApplySettings(TextBoxConfig config)
{
//Doing something
}
public static TextBox ApplySettings(Action<TextBoxConfig> modifier)
{
var config = new TextBoxConfig();
modifier(config);
return ApplySettings(config);
}
}
I had to add some semicolons after the statements. And I'd prefer the other answer. But I hope this fulfills your desire for lambda expressions.
Not exactly the same as your wish, but pretty close:
TextBox txt = Util.ApplySettings(new TextBoxConfig()
{
Caption = "Name",
FieldName = "UserName",
Width = 20,
Name = "txtName"
});
Note the commas after each setting. See http://msdn.microsoft.com/en-us/library/vstudio/bb397680.aspx.

Categories