So I do have a WinForm in my Programm, which contains a series of each a ComboBox and two TextBoxs. There are atm 8 Lines, but this will increase to a total of at least 32, therefore I would like to work with an Array or similar. How do I do that?
My current working, method is that a create a new array of TextBoxes/ComboBoxes which I assign the designated Elemt of the WinForm, manually. Therefore I have a list like this:
tbGU[0] = tbGU1;
tbGO[0] = tbGO1;
cbS[0] = cbS1;
Of course, this looks awful and isn't great if it's copied many times. Anyone got a Solution to my Problem?
I need to access the SelectedIndex of the ComboBox and the Text of the TextBoxes.
I was hoping that I could avoid having to create all the Elements manually by code.
One simple solution is to use the array initializer syntax:
ComboBox[] cbS = new[] { cbS1, cbS2, cbS3 ... };
Another way of doing this would be to get rid of the variables cbS1, cbS2 ... cBSn altogether and create the controls in a for loop.
ComboxBox[] cbS = new ComboBox[32];
// declare the text box arrays here as well
for (int i = 0 ; i < cbS.Length ; i++) {
cbS[i] = new ComboBox();
cbS[i].Location = ... // use "i" to help you position the control
// configure your combo box ...
this.Controls.Add(cbS[i]);
// do the same for the text boxes.
}
A third way is to create a custom control:
// name this properly!
public class MyControl: UserControl {
public ComboBox CbS { get; }
public TextBox TbGU { get; }
public TextBox TbGO { get; }
public MyControl() {
// create and configure the combo box and text boxes here ...
}
}
Then you can use a for loop to create lots of MyControls.
Related
I am working on WinForms UI and we have a requirement where we need to add repeating controls dynamically.
I managed to create a UserControl with all labels and text boxes and adding them like this:
for (int i= 0; i < 4;i ++) {
tableLayoutPanel1.Controls.Add(new MyUserControl(),1,1);
//1,1 represent 1st row, 1st column of tablelayoutpanel
}
Now I am not able to find a way to bind different data to each control. For example: I need to display different contact information in each textbox every time a new user control is added. But since its the same UserControl, the textbox and labels have the same name and i am not sure how to bind different data using same UserControl.
I need something like this: I am able to add controls repeatedly, but not able to bind data:
Screenshot
Any help would be greatly appreciated.
If you are creating custom user-controls. You can provide data-binding capabilities for your likes. You could use a parameter in the constructor to pass data in:
public MyUserControl(MyData mydata):this()
{ ...
}
You can provide a property, to set the required data later:
public class MyUserControl()
{
...
public MyData MyDataSource {get;set;}
}
You cold pass in a function to collect data:
public MyUserControl(func<MyData> mydata):this()
{
}
Or some sort of service to retrieve the data:
public MyUserControl(IMyService myService):this()
{
Textbox1.Text = myService.GetImportantText();
}
If MyData implements INotifyPropertyChanged (or any custom event), you will be able react to data changes and display them.
I guess you know how many controls need to be created. If yes, you know also why and which data you need provide.
An Example of adding the UserControl to the TableLayoutPanel
for (int nCount = 0; nCount < 2; nCount++)
{
CheckUserControl uc = new CheckUserControl();
//If required Assign Value to the control
uc.strValue = "Item " + nCount;
uc.strTag = nCount.ToString();
//You can pass the Column and Row value dynamically
tableLayoutPanel1.Controls.Add(uc, 1, 1);
}
Now you can use Tag Value to bind the data to the appropriate UserControl
I have 100 sequential buttons and checkboxes showed in a Windows Forms application, and a database where some numbers are saved.
My aim is to hide the buttons and checkboxes according to the number saved in the database.
For example, in my database I have 4 numbers: 2, 4, 9, and 10. So I want to hide button2, checkbox2, button4, checkbox4, button9, checkbox9, button10, checkbox10.
Here's what I tried:
SqlCeCommand cmnd = con.CreateCommand();
cmnd.CommandText = "SELECT * FROM register_db WHERE semester = #s AND department = #d AND course = #c";
cmnd.Parameters.AddWithValue("#s", semester);
cmnd.Parameters.AddWithValue("#d", department);
cmnd.Parameters.AddWithValue("#c", course);
SqlCeDataReader rd = cmnd.ExecuteReader();
while (rd.Read())
{
string number = rd[0];
button[number].hide();
checkbox[number].hide();
// these are the main things that I didn't know how to do
}
Assuming your controls are named like that, you can access them through the form’s Controls collection:
string number = rd[0];
this.Controls["button" + number].Hide();
this.Controls["checkbox" + number].Hide();
But you should really put them in a separate list, and probably group them into panels in a StackedPanel, or a CheckedListBox.
All Windows Forms controls have a .Hide() method. The code is case-sensitive, so you're not calling it correctly. It needs to be capitalized:
button[number].Hide();
checkbox[number].Hide();
Alternatively, you can set their .Visible property:
button[number].Visible = false;
checkbox[number].Visible = false;
Or are you having trouble with the array of controls? Names like button1, button2, etc. aren't particularly meaningful in most cases. But if your controls are indeed meant to be part of an ordered collection of controls, you can probably just create a collection on your form to represent them:
protected IList<Button> Buttons
{
get
{
return new List<Button>
{
button1, button2, button3; // etc.
};
}
}
Accessing the numeric values in the names themselves would otherwise be a job for reflection, which in many cases isn't really the direction you want to go. It's better to build a structure which meets your needs than to circumvent a structure which doesn't.
With this you can access the controls as an array:
Buttons[number].Hide();
Checkboxes[number].Hide();
You can take it a step further and combine the two, since they pair together. Something like this:
private class ControlGroup
{
public Button Button { get; set; }
public CheckBox CheckBox { get; set; }
public void Hide()
{
this.Button.Hide();
this.CheckBox.Hide();
}
}
(You can add further error checking within that class to guard against nulls, etc. Probably give the class a more meaningful name, too.)
Then your collection becomes:
protected IList<ControlGroup> ControlGroups
{
get
{
return new List<ControlGroup>
{
new ControlGroup { Button = button1, CheckBox = checkbox1 },
new ControlGroup { Button = button2, CheckBox = checkbox2 },
new ControlGroup { Button = button3, CheckBox = checkbox3 }
// etc.
};
}
}
This keeps things logically grouped together where appropriate into a smarter data structure, which makes the calling code easier:
ControlGroups[number].Hide();
I have a listview (lvMap) with 3 columns (Map, From, To) I am trying to write a method that is called as soon as my form loads. this method should look at the listview items and and sort them only by 2 columns "Map" and "From" in ascending order, i dont want it to sort the "To" column. I have written the code below but it sorts every single column, is there a way to leave a column out of the sorting procedure. Thanks.
private void sortListViewOrder()
{
lvMappings.Sorting = SortOrder.Ascending;
lvMappings.Sort();
}
I would suggest you consult the following MSDN article, hopeful it answers your question:
http://support.microsoft.com/kb/319401
Basically you need to create a ListViewColumnSorter instance and add it to your ListView control.
From there on the article will have enough information :)
You have to do it using ListViewColumnSorter . Following KB Link has the sample code to do that.
http://support.microsoft.com/kb/319401
You can assign the column to be sorted using,
Create an instance of a ListView column sorter and assign it
// to the ListView control.
lvwColumnSorter = new ListViewColumnSorter();
this.listView1.ListViewItemSorter = lvwColumnSorter;
lvwColumnSorter.SortColumn = Column;
I needed this feature, or function, in the ListView control. The suggestion to use an Extension Class I first saw here. I tried it and it worked, but only now I can tell how to easily do it. Refer to this reference question:
How to prevent flickering in ListView when updating a single ListViewItem's text?
Step 1: Create a (separate) ControlExtensions class in your project, and paste this code:
using System.Reflection;
using System.Windows.Forms;
namespace [YourNameSpace]
{
public static class ControlExtensions
{
public static void DoubleBuffering(this Control control, bool enable)
{
var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
}
}
}
Step 2: Define the following in the WinForms that has the ListView:
private ListViewColumnSorter lvwColumnSorter = null;
After InitializeComponent(); section, define the following:
lvwColumnSorter = new ListViewColumnSorter();
this.lvwRunningProcesses.ListViewItemSorter = lvwColumnSorter;
lvwColumnSorter._SortModifier = ListViewColumnSorter.SortModifiers.SortByText;
Step 3: In the Form Load event, add these lines after the List View is populated:
// Sort in ascending order Column 0
lvwColumnSorter.SortColumn = 0;
lvwColumnSorter.Order = SortOrder.Ascending;
this.lvwRunningProcesses.Sort();
That's it!
I'm not very experienced on c#. I'm working with winforms and I'm looking for a way to create something like a list of elements with this template , something like the autocompletion list of visual studio.
Is it possible to do? Shall I use listbox or listview?
EDIT
Sorry my question wasn't clear I don't want to create an autocomplete but what i want to create is something like this a list of things with an icon next to the text of that thing.
As I understand from your question, you can create custom UserControl or create a Form and put ListBox in it. If you use From be sure that you change border style layout, just set it to none. After creation for use it you should create form and show it where you want like this:
FrmAutoComplete x = new FrmAutoComplete();
x.Show();
you can put this form in ToolTipItem and show it.
Good luck.
THis is a quick and dirty example of using images in your Listview control. Since I don;t have a lot of information about what you plan to do, I tried to keep is simple.
In short, you need to load some images into one of the ImageLists (Large or Small) built into the Listview control and assign them keys so that you can assign them to specific list items as you add them.
The trick to this is determining which image to use for a specific list item (assuming there are different images assigned to different list items depending on some differentiating factor. For this example, I used an arbitrary assignment of "cars" or "trucks," and simply decided that the first five items in the list would be cars, and the last five would be trucks. I then assigned each image appropriately, using the image key as I added each listview item. You can do this for more complex scenarios, and when using the image key, it does not matter what order the items are added.
For this use case, you will want to create or use images with dimensions of 16 x 16 pixels. I went ahead and added two images to my project resource file, then simply accessed them using the project Properties.Resources name space. There are other ways to do this as well, but this is the most convenient for me.
Hope that helps.
public partial class Form1 : Form
{
static string CAR_IMAGE_KEY = "Car";
static string TRUCK_IMAGE_KEY = "Truck";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.SetupListview();
this.LoadListView();
}
private void SetupListview()
{
var imgList = new ImageList();
imgList.Images.Add("Car", Properties.Resources.jpgCarImage);
imgList.Images.Add("Truck", Properties.Resources.jpgTruckImage);
var lv = this.listView1;
lv.View = View.List;
lv.SmallImageList = imgList;
}
private void LoadListView()
{
for(int i = 1; i <= 10; i++)
{
string currentImageKey = CAR_IMAGE_KEY;
if(i > 5) currentImageKey = TRUCK_IMAGE_KEY;
var item = this.listView1.Items.Add("Item" + i.ToString(), currentImageKey);
}
}
in my Win Forms app I create an array of dynamic custom controls inside a loop. These, lets call them 'boxes', are like my basic pieces of information. I also create string arrays in other parts of the code that contain the information of this 'boxes', so that for example string[3] is a variable of box[3] and so does stringa[3], stringb[3], stringc[3]... all the arrays with the same index are related to the box with that index. Hope I make myself clear.
Only 2 of this strings are shown in 2 labels inside each custom control 'box' in the array, but the others are there because I want to make something so that when the user clicks one of these controls the other strings can be shown in another control. Sort of something like "More Information...". All the 'boxes' in the array need to have the same event handler because I create +100.
To put it more into context, each custom control 'box' in the array shows the Symbol and the Price of a stock and I want that when the user clicks on each stock more quote information is shown on another special control which is like a placeholder for "More info".
I am thinking of 2 ways to do it:
If I could "detect" the index of the clicked control (which is the same in the strings related to it), I could just set this to an int j and all I have to do is show all the strings a,b,c... with index j. Unfortunately I cannot find a way to do this, maybe it is not even possible.
The other way I have thought is to create some properties for my custom control which "store" this variables, and in my app instead of assigning strings I would set properties for each control, which I could later retrieve when the control is clicked. I haven't tryed this because I don't know exactly how to do it.
What do you think? Do you know how can I achieve this or do you have a different idea that will work? Please help! Thanks in advance.
It's kind of a broad implementation question since there are countless ways you could implement something like this.
If you are creating two collections, one with the buttons and one with the information, you potentially could just assign each of the buttons 'Tag' properties to point to the corresponding info and assign a generic OnClick event handler that displays the info.. something like:
infoControl.text = ((InfoClass)((Button)Sender.Tag)).pieceOfInformation;
But again there are many ways to do this, and the choice comes down to how you store your information.
For your first method, you could have a property of your custom control that is the index.
public class Box : Control
{
// ...existing code
private int index;
public int Index
{
get
{
return index;
}
set
{
index = value;
}
}
}
OR
For your second method, you could have a property of your custom control that is the additional info string.
public class Box : Control
{
// ...existing code
private string extraInfo;
public string ExtraInfo
{
get
{
return extraInfo;
}
set
{
extraInfo = value;
}
}
}
In either case, you could then access the proper information right in your click handler for the "box".
i don't know about the first way - got to noodle around more, but in the second way you can extended your custom or built-in control: for example:
public class ExtendedLabel: Label
{
public string[] MoreInfo { get; set; }
}
and initialize it
public TestForm()
{
InitializeComponent();
ExtendedLabel label = new ExtendedLabel();
label.MoreInfo = new string[] { "test" };
this.Controls.Add(label);
label.AutoSize = true;
label.Location = new System.Drawing.Point(120, 87);
label.Name = "label1";
label.Size = new System.Drawing.Size(35, 13);
label.TabIndex = 0;
label.Text = label.MoreInfo[0];
}
And later in your event handler you can use the inside information