I try to write a program where you can select an item from a drop-down menu and it returns its serial number. The problem is that the items change and that is why I want to read the values from a file and fill the drop-down with the values.
I imagined that I would have a file that looks something like this:
Toaster;220:
Microwave;3021:
In this example, I would divide the product and the id with a semicolon and the number ends with a colon. The drop-down menu would only show the products (in this case Toaster and Microwave) and would return the values 220 or 3021
Is there any easy way to realize that in C#?
Its really easy to do that but you don't provide much information a bout the stack of technologies that you use beside c#. Are you trying to do this in a web app such as (asp.net or asp.net core) desktop one (wpf, winforms) or uwp application. If so are you using any controls such as devexpress, infragistics, syncfusion, telerik...? There are many ways to do this if you provide some more information a bout your work environment I would be happy to help. I can give you quick example with wpf or either winforms application since you metioned that you are trying to write a program. you could go to Syncfusion.com and download their controls since they are free to use in noncommercial products and happen to have great documentation(installation is easy likewise especially if you use visual studio) then you go and create winform syncfusion project. Then look into the documentation for the events that you need in order to get on selection changed. Other workaround would be in pure winforms application here is how you can do this, first you go and create new application then you add a combo box with on selection changed event and data bound option. Then you create on load event for the form that would be used to add the items from the text file then you don't generally need but I prefer to create a structure for my new object if you managed to get here you can add a file reader to read you text then bind the information to the new list of the class that you just created. After that you bind the list of items to the combobox and create a label that would hold the displayed id. then its simple on selectionchanged event you take the selected item and cast it to the class that you created and bind the id of the class to the label and you have the functionality that you look for. you can look the code samples that I would provide
private List<FileLine> Source { get; set; }
public class FileLine
{
public string Text { get; set; }
public int Id { get; set; }
}
private void Form1_Load(object sender, EventArgs e)
{
Source = GetFiles();
comboBox1.Items.AddRange(Source.ToArray());
}
public List<FileLine> GetFiles()
{
var files = new List<FileLine>();
int counter = 0;
string line;
// Read the file and display it line by line.
System.IO.StreamReader file =
new System.IO.StreamReader("Items.txt");
while ((line = file.ReadLine()) != null)
{
var item = line.Split(';').ToList();
files.Add(new FileLine { Text = item.FirstOrDefault(), Id = int.Parse(item.LastOrDefault()) });
counter++;
}
file.Close();
return files;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var item = comboBox1.SelectedItem as FileLine;
IdLabel.Text = item.Id.ToString();
}
this is how my controller for the winform1 :form look like if you don't want to bother adding new items to the view you can copy this to a new form with name form1 inside the initialize components which you can access with F12 key
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.IdLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// comboBox1
//
this.comboBox1.DisplayMember = "Text";
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(87, 64);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(121, 21);
this.comboBox1.TabIndex = 0;
this.comboBox1.ValueMember = "Id";
this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
//
// IdLabel
//
this.IdLabel.AutoSize = true;
this.IdLabel.Location = new System.Drawing.Point(87, 128);
this.IdLabel.Name = "IdLabel";
this.IdLabel.Size = new System.Drawing.Size(0, 13);
this.IdLabel.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.IdLabel);
this.Controls.Add(this.comboBox1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.Label IdLabel;
Generally I gave the lecture for the controls because its simply easy to work with and look better, but you can feel free to use whatever you want. Here is a link to working sample http://www.filedropper.com/windowsformsapp1_1
Related
I'm working on an inventory program and have finished the main functionality as a command line console app. I am now working on a version for winforms. I want to enable it to dynamically generate a Groupbox that holds some textboxes. I'd rather not design 50+ lines of multiple textboxes. Keep in mind I'm rather new to programming, having started with C# a year ago. I know next to nothing on Winforms.
I've tried to use dynamic item = new Groupbox();as a similar method allowed generation of objects at runtime. In the command line app, the way it works is that based on information given, a certain amount of objects are passed into the list _AllItems. I was thinking of generating the Groupboxes by using:
private void InitializeGroupBox()
{
foreach (Product product in Product._AllItems)
{
dynamic Item = new GroupBox();
}
}
But I have the feeling I'm nowhere near the correct method. Thanks to anybody who helps.
You will need to learn a bit more, but here is what I usually do to achieve what you asked.
internal class DynamicForm : Form
{
private FlowLayoutPanel mFlowLayoutPanel;
public DynamicForm()
{
mFlowLayoutPanel = new FlowLayoutPanel();
mFlowLayoutPanel.Dock = DockStyle.Fill;
// Add to this Form
this.Controls.Add(mFlowLayoutPanel);
InitializeGroupBox();
}
private void InitializeGroupBox()
{
mFlowLayoutPanel.SuspendLayout(); // Performance
for (int i = 1; i <= 20; i++) {
var groupBox = new GroupBox();
groupBox.Text = "GroupBox #" + i;
groupBox.Size = new Size(200, 50);
var textBox = new TextBox();
textBox.Dock = DockStyle.Fill;
// Add the TextBox to GroupBox
groupBox.Controls.Add(textBox);
// Add to this Form
mFlowLayoutPanel.Controls.Add(groupBox);
}
mFlowLayoutPanel.ResumeLayout(); // after suspend, resume!
}
}
So, I have a project in which I allow editing of a DatagridView in a separate Form. I pass in the DatagridView object and its parent container to the constructor of the new Form.
This works well and I can edit the grid that way. But when I try to give it back by changing its parent back to the original form, I get this error :
Cannot convert type 'System.Windows.Forms.MenuItem' to 'System.Windows.Forms.Control'
Now both MenuItem, and Manual Entry directly inherit from Form.
Here is my code that takes the DataGridView from the original form (which works correctly)
public partial class ManualEntry : Form
{
private Data d;
DataGridView DataView;
MenuItem mi;
public ManualEntry(DataGridView ExcelDisplay, Data d, MenuItem menuItem)
{
InitializeComponent();
//Take the Datagridview from the MenuItem.
DataView = ExcelDisplay;
DataView.Parent = this;
mi = menuItem;
this.d = d;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(15, 76);
this.DataView.Size = new System.Drawing.Size(237, 211);
this.DataView.TabIndex = 5;
this.DataView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataView_CellContentClick);
}
Now here is me trying to give it back. and of course it produces the error above.
private void FinishButton_Click(object sender, EventArgs e)
{
//move the datagridview back to the original form and give its old size,shape, and position back.
DataView.Parent = mi;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(12, 167);
this.DataView.Name = "ExcelDisplay";
this.DataView.Size = new System.Drawing.Size(250, 256);
this.DataView.TabIndex = 7;
this.Close();
}
I have also tried casting which does not work either.
DataView.Parent = (System.Windows.Forms.Control)mi;
Update
This shows that MenuItem is a Form as well.
public partial class MenuItem : Form
{
This shows that MenuItem is a Form as well.
Well, you have not convinced the compiler. You can tell from the error message that it thinks that your "mi" variable is a System.Windows.Forms.MenuItem. Do not use .NET class names for your own types, that just makes your life harder to troubleshoot bugs like this. Don't use variable names like "d" either. Choosing good names is a Very Important programmer's job.
The proper way is to preserve the control's Parent property so you can set it back. Roughly:
public partial class ManualEntry : Form
{
private Data DataViewData;
private DataGridView DataView;
private Point DataViewLocation;
private Control DataViewParent;
public ManualEntry(DataGridView ExcelDisplay, Data data)
{
InitializeComponent();
this.DataViewData = data;
this.DataView = ExcelDisplay;
this.DataViewLocation = ExcelDisplay.Location;
this.DataViewParent = ExcelDisplay.Parent;
this.DataView.Parent = this;
// etc...
}
protected override void OnFormClosing(FormClosingEventArgs e) {
base.OnFormClosing(e);
if (!e.Cancel) {
DataView.Parent = this.DataViewParent;
DataView.Location = this.DataViewLocation;
// etc..
}
}
}
I am new to Winforms and C# so this may sound like a stupid question. I have the class shown below for creating a form to be displayed as a modal dialog.
class FrmDelivery : Form
{
ListBox s;
public FrmDelivery()
{
s = new ListBox();
s.DataSource = new List<int>(){1,2,3,4};
s.Update();
s.Show();
}
}
However for some reson when I use the ShowDialogmethod to display this form it doesnt show anything in it. What should I do to add a list box to this form ?
EDIT:
I use the code to display the form:
FrmDelivery frm = new FrmDelivery();
frm.ShowDialog();
One note - WPF uses Windows, not Forms, so I'm not clear why you're deriving from Form rather than Window. But I'll answer as if you were talking about a WPF Window as your "form".
First, something will need to display the Window. Currently, the code provided doesn't show the Window, it attempts to show a ListBox.
Second, you either need to add a LayoutPanel to the window and add your ListBox as a child of the layout panel. Layout Panels come in many flavors, such as Grids and StackPanels and Canvases based on what type of layout you want.
Or, you can set the Content of the Window to be your ListBox. This will mean the only thing on the Window is your ListBox', so if you want multiple visual elements on yourWindow`, you'll need to use a layout panel.
The second approach would look like
this.Content = s;
For the first approach, I'd recommend reading up on Layout Panels in WPF. Here is one tutorial and here is the MSDN topic on layout. A google search will yield many more results.
I suggest you create a new form using Add|New Item|Windows Form.
You will then get a design surface to which you can add a listbox, and generated code which will initialize your form and listbox correctly. In particular your form and listbox will gain default sizes which they don't have currently.
Your code (in say Form1.cs) will then be similar to this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.listBox1.DataSource = new List<int> { 1, 2, 3, 4 };
}
public int? SelectedValue
{
get
{
return (int?)this.listBox1.SelectedValue;
}
}
}
Plus there will be a load of code in Form1.Designer.cs similar to
....
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.listBox1 = new System.Windows.Forms.ListBox();
this.SuspendLayout();
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.Location = new System.Drawing.Point(30, 37);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(120, 95);
this.listBox1.TabIndex = 0;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.listBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
And you could use your form like this:
private void button1_Click(object sender, System.EventArgs e)
{
using (var form = new Form1()) // you should dispose forms used as dialogs
{
if (DialogResult.OK == form.ShowDialog()) // optional (you could have OK/Cancel buttons etc
{
Debug.WriteLine(form.SelectedValue ?? -1);
}
}
}
You should not only add the controls to the collection but also set up his caracteristics.
Size & emplacement, at least.
class FrmDelivery : Form
{
ListBox s;
public FrmDelivery()
{
s = new ListBox();
s.Location = new System.Drawing.Point(0, 0); //relative to the parent control (not an absolute value, so)
s.Name = "listBox1";
s.Size = new System.Drawing.Size(120, 95);
s.DataSource = new List<int>(){1,2,3,4};
this.Controls.Add(s); //it will add it to the form but you can add it to another control, like panel.
}
}
Hope it will help
You need to add the listbox to the controls collection:
ListBox s;
public FrmDelivery()
{
s = new ListBox();
s.DataSource = new List<int>() { 1, 2, 3, 4 };
this.Controls.Add(s);
}
This will get the control onto your form for you, though there are a bunch of other properties you will likely want to set (e.g. to get it looking how you want) - as others have mentioned, you can see how the designer does this in the code behind by putting a listbox onto a form and examining the resulting code.
Please see if you have the InitializeComponent() in the default construct commented out. It usually initializes all the control of the form on FormLoad.
I am trying to add an activeX control in an user control in a C# windows form based project.
Now if I add that activeX component from the tools menu then by simply using drag and drop I am able use the activeX control.
But when I try to add that one at run time using C# code then it throw following exception:
"Exception of Type
'System.Windows.Forms.AxHost=InvalidActiveXStateException' was
thrown".
Using CreateControl() I am able to get rid of this exception but now the activeX control does not appear on the form.
When are you adding the control and where are you adding it on the form?
You would normally load the control in the constructor just after the component is initialized:
public FormRecalculation()
{
InitializeComponent();
loadDataSelector();
}
If there are any associated license keys you will need to set them and add them to the appropriate container on the form:
private void loadDataSelector()
{
//Initialize the DataSelector
DataSelector = new AXQDataSelector(getClsidFromProgId("QDataSelLib.QDataSel"));
if (DataSelector != null)
{
System.Reflection.FieldInfo f =
typeof(AxHost).GetField("licenseKey",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
f.SetValue(DataSelector, "license-here");
splitContainer1.Panel2.Controls.Add(DataSelector);
((System.ComponentModel.ISupportInitialize)(DataSelector)).BeginInit();
this.DataSelector.Dock = System.Windows.Forms.DockStyle.Fill;
this.DataSelector.Enabled = true;
this.DataSelector.Location = new System.Drawing.Point(0, 0);
this.DataSelector.Name = "DataSelector";
this.DataSelector.Size = new System.Drawing.Size(324, 773);
this.DataSelector.TabIndex = 0;
splitContainer1.Panel2.ResumeLayout();
((System.ComponentModel.ISupportInitialize)(DataSelector)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
else
{
return;
}
}
This is actually for a wrapped OCX but you get the idea...
ok, after some changes the code looks like this. Here at runtime four tabs are created. Initially, on first tab the control is displayed. When user clicks on other tabs page activex control added on those pages dynamically. (This code is written for a .net usercontrol. On run time this usercontrol is added to the form)
private void Populate()
{
int position;
int i = 0;
//here children in list of string type
foreach (string child in children)
{
this.productLineTabs.TabPages.Add(child);
AxSftTree treeadd = loadtree(this.productLineTabs.TabPages[i]);
this.tree.Add(treeadd);
this.tree[i].Columns = 2;
this.tree[i].set_ColumnText(0, "Col1");
this.tree[i].set_ColumnText(1, "Col2");
position = this.tree[i].AddItem(child);
i++;
}
form plv = new form();
plv.Controls.Add(this);
plv.Show();
}
private AxSftTree loadtree(TabPage tab)
{
AxSftTree treeobject = new AxSftTree();
((System.ComponentModel.ISupportInitialize)(treeobject)).BeginInit();
SuspendLayout();
tab.Controls.Add(treeobject);
treeobject.Dock = DockStyle.Fill;
ResumeLayout();
((System.ComponentModel.ISupportInitialize)(treeobject)).EndInit();
return treeobject;
}
You can find some details about this implementation on this page:
http://newapputil.blogspot.in/2013/11/how-to-add-activex-control-at-run-time.html
I am creating an application where a user will input grades and the program will output the weighted average. On load, it will ask for the number of categories for the assignments. The program will then dynamically create textboxes for the user to input information. The problem is that I can not figure out how to read the text that is inputed after I create the textboxes. Here is my code:
TextBox txtbx = new TextBox();
txtbx.Text = "";
txtbx.Name = "txtbx1";
txtbx.Location = new Point(10, 10);
txtbx.Height = 20;
txtbx.Width = 50;
Controls.Add(txtbx);
How can I change this code so I can find the current text in the box when the user submits?
If you are dynamically generating controls then obviously you won't be able to have a field for each one. But if you are trying to access the Controls collection for a named control, the ControlCollection can be indexed by name. After adding the text box with the specified name, you can simply do:
TextBox txtbx = (TextBox)Controls["txtbx1"];
You could use the FindControl method of the Page class.
This method takes a parameter which is the TextBox's ID, which you have to set upon creation:
txtbx.ID = "txtbx1";
Then you can select it:
TextBox txtbx1 = (TextBox)FindControl("txtbx1");
and use it.
Edit: Since the initial question added that he is refering to Windows Forms, my reply above is off-topic.
In Windows Forms, you should simply use a class member variable instead of a local variable. E.g.:
public partial class MyForm
{
...
private TextBox txtbx;
...
private void createControls()
{
txtbx = new TextBox();
txtbx.Text = "";
txtbx.Name = "txtbx1";
txtbx.Location = new Point(10, 10);
txtbx.Height = 20;
txtbx.Width = 50;
Controls.Add(txtbx);
}
private void someOtherFunction()
{
// Do something other with the created text box.
txtbx.Text = "abc";
}
}
This code for the Dynamically Add Textbox On Button Click
int count = 1;
public System.Windows.Forms.TextBox AddNewTextBox()
{
System.Windows.Forms.TextBox txt = new System.Windows.Forms.TextBox();
this.Controls.Add(txt);
txt.Top = count * 25;
txt.Left = 100;
txt.Text = "TextBox " + this.count.ToString();
count = count + 1;
return txt;
}
private void Onbutton_Click(object sender, EventArgs e)
{
//Call the method AddNewTextBox that uses for Dynamically create Textbox
AddNewTextBox();
}
I hope this code will help you .
Thank You
Happy Coding:)
Keep a list of references of all text boxes on the form. Add the textBox reference to the list when you create them dynamically.
Then you can simply iterate through all text boxes in the list when you want to read their text.
Make sure that you name the text boxes as per their related category names. Then you can also Find the control in the list by their names.
class MyForm : Form
{
IList<TextBox> _textBoxes = new List<TextBox>();
private void AddTextBox(string categoryName){
var myTextBox = new TextBox();
myTextBox .Name = categoryName + "txtbx";
// set other properties and add to Form.Controls collection
_textBoxes.Add(myTextBox);
}
private TextBox FindTextBox(string categoryName)
{
return _textBoxes.Where( t => t.Name.StartsWith(categoryName)).FirstOrDefault();
}
}
All you need to do is set up an OnClick listener for your submit button and have it do something like this
private void OnSubmit(object sender, EventArgs args)
{
string yourText = txtbx.Text;
}
You'll have to keep a reference to the text box after you create it. yourText will contain the value you need. Hope this helps