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.
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!
}
}
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
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 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 have a program that I want each person to have their own tab, each tab would be identical, however I would like to remove a tab if I need to.
private void addPerson(string name)
{
TabPage tmp = new TabPage();
ListView tmpList = new ListView();
Button tmpButton = new Button();
this.SuspendLayout();
this.tabFrame.SuspendLayout();
tmp.SuspendLayout();
tmpList.SuspendLayout();
tmpButton.SuspendLayout();
...
//build the controll itself
tmp.Controls.Add(tmpButton);
tmp.Controls.Add(tmpList);
tmp.Location = new System.Drawing.Point(4, 22);
tmp.Name = name.Replace(' ', '_');
tmp.Padding = new System.Windows.Forms.Padding(3);
tmp.Size = new System.Drawing.Size(284, 240);
tmp.TabIndex = 3;
tmp.Text = name;
tmp.UseVisualStyleBackColor = true;
//add it to frame
this.tabFrame.Controls.Add(tmp);
tmpButton.ResumeLayout(true);
tmpList.ResumeLayout(true);
tmp.ResumeLayout(true);
this.tabFrame.ResumeLayout(true);
this.ResumeLayout(true);
{
Name will be in the form "Scott Chamberlain" so I remove the spaces and use underscores for the name field. I can add tabs fine, they show up correctly formated, however when I try to remove the tab using the code:
private void removePerson(string name)
{
this.SuspendLayout();
this.tabFrame.SuspendLayout();
this.tabFrame.Controls.RemoveByKey(name.Replace(' ', '_'));
this.tabFrame.ResumeLayout(true);
this.ResumeLayout(true);
}
The tab does not disappear from my program. What am I missing to remove a tab?
(source: codinghorror.com)
Creating a simple TabPage with a specific Name and adding it to Controls or TabPages works and so does removing it with RemoveByKey on both Controls and TabPages.
Is there any code that might later change the name?
Use tabFrame.TabPages instead of tabFrame.Controls, for both the Add() and RemoveByKey() operations.
TabPages is a more specified version of Controls, and if such a situation occurs you are better of with the more specialized option.