How to create several dynamic listview Unknown number of listveiw - c#

In my project I need to create several lisview dinamically, I have a array with some value string[] = array{"BILL", "ORDER", "DELEVERY FORM", "RCL", "ESTIMATION", ...}; And I would like create a listview to each value from array.
void CreateListView(string[] array)
{
foreach(value in array)
{
ListView listView[value] = new ListView();
this.Controls.Add(listView[value]);
}
}

From my understanding you want to create the listviews and name them according to the given array. If that is the case, then this should satisfy.
void CreateListView(string[] array)
{
foreach (var value in array)
{
ListView listView = new ListView {Name = value};
Controls.Add(listView);
}
}

Related

checking several Lists List<int> for a certain number doesn't work

I am trying to know if a number I pass to the function is contained in any of the lists I have. Here is an extract of the code. I have initialized the list grid as it is said in many similar posts here, but that doesn't work.
The error says
"System.NullReferenceException: 'Object reference not set to an instance of an object.'"
referring to grid. I know it seems duplicated, but I have checked the others posts similar to this and I can not find a specific answer to my problem.
public partial class MainWindow : Window
{
//This list is much bigger
public List<int> grid1 = new List<int>();
public List<int> grid2 = new List<int>();
public List<int> grid3 = new List<int>();
public List<int> grid4 = new List<int>();
public List<int> grid5 = new List<int>();
public MainWindow()
{
InitializeComponent();
}
private bool numberValide(int number, int Grid) // Grid {1..5}
{
List<int> = new List<int>();
grid = (List<int>)this.FindName("grid" + Grid);
if (grid != null)
{
if (!grid.Contains(number))
{
grid.Add(number); //the error is here
return true;
}
else
{
return false;
}
}
else
{
grid.Add(number); //error also here
return true;
}
}
}
The reason for your issue is FindName() is looking for a XAML element by that name, its not going to check for class members. So this line of code:
grid = (List<int>)this.FindName("grid" + Grid);
Will always be null, because FindName("grid" + Grid) will return null, then you are casting that null to a List<int>. So grid will be a null List<int>
Having all these Lists in your class is a pretty bad design. You can simplify things a bit by using a Dictionary. I am not entirely sure I follow what your logic is, but this is my attempt to convert:
public partial class MainWindow : Window
{
public Dictionary<int, List<int>> gridDictionary = new Dictionary<int, List<int>>();
private bool numberValide(int number, int gridIndex) // Grid {1..5}
{
//Checks if dictionary has an entry at gridIndex
if(gridDictionary.ContainsKey(gridIndex))
{
if (!gridDictionary[gridIndex].Value.Contains(number))
{
//Add number to list in dictionary
gridDictionary[gridIndex].Value.Add(number);
return true;
}
else
{
return false;
}
}
else
{
//Adds a new entry to the dictionary with a list containing number
gridDictionary.Add(gridIndex, new List<int>() { number });
return true;
}
}
Keep in mind that Dictionaries must have unique keys, so you couldn't do:
dictionary.Add(1, "one");
dictionary.Add(1, "uno");
That would throw an exception because a duplicate key exists already. For your use case this should be fine because all your grid variables had to be uniquely named anyway to compile.
I suspect the problem here is that you think FindName will let you find a field in a class. That is not what it does. It finds a control in a window. grid1, grid2, etc are not controls. They are fields
If you want to find fields, you would have to use reflection...but, the better way would be to just have a List<List<int>> instead.
So:
List<List<int>> grids = new List<List<int>>();
Then somewhere (maybe the constructor) you populate that list:
for (var i=0; i < numberOfGrids; i++)
{
grids.Add(new List<int>());
}
And then later when you want to retrieve a grid in your numberValide:
var grid = grids[Grid]; // where Grid is the index to your Grid -
// your variable names are confusing
But now, since your original problem was to see if a number exists in any of your lists of ints, you can use Linq to simplify this greatly:
var doesExist = grids.Any(g => g.Contains(number));

Is it possible to do a ListViewItem array?

Is it possible to declare a ListViewItem array? E.g.
ListViewItem[] arrayItems;
If it's possible, how can I populate the array?
Is it possible to have the array which is not fixed size?
Yes ! It is possible to declare a List as an array.
For Specified length use below:
ListViewItem[] arrayItems = new ListViewItem[5];
arrayItems[0] = new ListViewItem("Text1");
arrayItems[1] = new ListViewItem("Text2");
// so on
For Unspecified length use below:
List<ListViewItem> arrayItems = new List<ListViewItem>();
arrayItems.Add(new ListViewItem("Text1"));
arrayItems.Add(new ListViewItem("Text2"));
// When you want to pass it as array, use arrayItems.ToArray();
Or if you have some list of objects with some text Property:
List<ListViewItem> arrayItems = dataSourceObject.Select(x => new
ListViewItem(x.TextProperty)).ToList();
It seems that you're looking for List<ListViewItem>, not for array (ListViewItem[]):
List<ListViewItem> myItems = new List<ListViewItem>();
// Just add items when required;
// have a look at Remove, RemoveAt, Clear as well
myItems.Add(new ListViewItem("Text 1"));
// When you want read/write the item do as if you have an array
ListViewItem myItem = myItems[0];
You can use Linq to obtain items from existing ListView:
myItems = listView1.Items
.OfType<ListViewItem>()
.ToList();
or append existing list:
List<ListViewItem> myItems = new List<ListViewItem>();
...
myItems.AddRange(listView1.Items.OfType<ListViewItem>());

Problems with Reflection on winforms

I have a winforms application.
I have a Populate method that creates a bunch of controls on each page on my tabcontrol. The Populate method takes two arguments - the tab page and a List with the strings for a bunch of labels. There is a separate List for each tabpage and the names of the Lists are the same as the names of the tabpages. I want to iterate through the pages and pass the appropriate List to the Populate method by name, i.e. to pass the List by a string that is its name. As far as I know I need Reflection for that.
Code:
namespace Test
{
public partial class Form1 : Form
{
List<string> Hongdoe = new List<string>(new string[] { "Chin", "Foa", "Hu", "Dan" });
List<string> Donfu = new List<string>(new string[] { "Faa", "Su", "Pi", "Mou" });
//TabPage1.Name = Hongdoe
//TabPage2.Name = Donfu
foreach (TabPage tp in Tab_Control.TabPages)
{
//I want to tell the program "Find the variable/list that is named as 'tp.Name'
var ListName = typeof(Form1).GetField(tp.Name)
Populate(tp, ListName);
}
}
void Populate (TabPage tp, List<string> list)
{
for (int i = 0; i < list.Count; i++)
{
//Create labels
Label lab = new Label();
lab.Text = list[i];
lab.Location = new Point(i * 10, i * 10));
tp.Controls.Add(lab);
}
}
}
But sofar it returns null. I also tried using "GetProperty", "GetValue" but no success.
(before I edited this question I used a variable to demonstrate my problem simply)
You don't need to use reflection. You can use a Dictionary<string, List<string>> and use list names (tab page names) as keys and list of strings as values. Then you can get a list using the key from dictionary.
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
private void ProductList_Load(object sender, EventArgs e)
{
//Initialize dictionary with keys and values
dictionary["page1"] = new List<string> { "string 1", "string 2" };
dictionary["page2"] = new List<string> { "string 3", "string 4" };
//...
}
Then you can call your Populate method this way:
Populate(tp, dictionary[tp.Name]);
Note
You don't need to pass list to the method and it's enough to pass TabPage to the method and you can get the list using dictionary[tabPage.Name]
You can use a TableLayoutPanel or a FlowLayoutPanel in tab pages to add labels to. This way they will be arranged automatically.
Just for learning purpose if you want to use reflection:
var list = (List<string>)this.GetType().GetField("Hongdoe",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance).GetValue(this);

How to fill a list view with the contents of List<string> in C#

I've a list
List<String> SampleList=new List<String>();
I need to fill a listView with the contents of the list
For example the "SampleList" contains
a
b
c
d
The listView should be filled like
S.No Item
1 a
2 b
3 c
4 d
Now i'm using for loop for this method
like
for(int i=0;i<SampleList.Count;i++)
{
listView1.Items.Add((i+1).ToString());
listView1.Items[i].SubItems.Add(SampleList[i]);
}
is there any other way to do this like data binding ?
Thanks in advance
Not quite like databinding, but you could use VirtualMode and RetrieveVirtualItem
listView1.VirtualMode = true;
listView1.RetreiveVirtualItem += new RetrieveVirtualItemEventHandler( this.RetrieveVirtualItem );
listView1.VirtualListSize = SampleList.Count;
private void RetreiveVirtualItem( object sender, RetrieveVirtualItemEventArgs e )
{
ListViewItem lvItem = new ListViewItem((e.ItemIndex + 1).ToString());
lvItem.SubItems.Add(SampleList[e.ItemIndex]);
e.Item = lvItem;
}
Does it have to be a ListView? ListBox is simple:
using (Form form = new Form())
{
List<string> strings = new List<string> {"abc", "def", "ghi"};
form.Controls.Add(new ListBox() {DataSource = strings});
Application.Run(form);
}
For a richer display, DataGridView would also do this, but you need an extra bit of indirection (since it supports multiple columns, it needs a wrapper object per row):
using (Form form = new Form())
{
List<string> strings = new List<string> {"abc", "def", "ghi"};
var indirect = (from s in strings
select new {Text = s}).ToList();
form.Controls.Add(new DataGridView() { DataSource = indirect });
Application.Run(form);
}
This also gives you opportunity to add in extra data, for example the number:
var indirect = strings.Select((s,i) =>
new {Index = i + 1, Text = s}).ToList();
Unfortunately windows forms ListView doesn't support DataBinding. But if you update the list frequently, maybe you can use INotifyProperty interface.

C#: How to add subitems in ListView

Creating an item(Under the key) is easy,but how to add subitems(Value)?
listView1.Columns.Add("Key");
listView1.Columns.Add("Value");
listView1.Items.Add("sdasdasdasd");
//How to add "asdasdasd" under value?
You whack the subitems into an array and add the array as a list item.
The order in which you add values to the array dictates the column they appear under so think of your sub item headings as [0],[1],[2] etc.
Here's a code sample:
//In this example an array of three items is added to a three column listview
string[] saLvwItem = new string[3];
foreach (string wholeitem in listofitems)
{
saLvwItem[0] = "Status Message";
saLvwItem[1] = wholeitem;
saLvwItem[2] = DateTime.Now.ToString("dddd dd/MM/yyyy - HH:mm:ss");
ListViewItem lvi = new ListViewItem(saLvwItem);
lvwMyListView.Items.Add(lvi);
}
Like this:
ListViewItem lvi = new ListViewItem();
lvi.SubItems.Add("SubItem");
listView1.Items.Add(lvi);
Suppose you have a List Collection containing many items to show in a ListView, take the following example that iterates through the List Collection:
foreach (Inspection inspection in anInspector.getInspections())
{
ListViewItem item = new ListViewItem();
item.Text=anInspector.getInspectorName().ToString();
item.SubItems.Add(inspection.getInspectionDate().ToShortDateString());
item.SubItems.Add(inspection.getHouse().getAddress().ToString());
item.SubItems.Add(inspection.getHouse().getValue().ToString("C"));
listView1.Items.Add(item);
}
That code produces the following output in the ListView (of course depending how many items you have in the List Collection):
Basically the first column is a listviewitem containing many subitems (other columns). It may seem strange but listview is very flexible, you could even build a windows-like file explorer with it!
I've refined this using an extension method on the ListViewItemsCollection. In my opinion it makes the calling code more concise and also promotes more general reuse.
internal static class ListViewItemCollectionExtender
{
internal static void AddWithTextAndSubItems(
this ListView.ListViewItemCollection col,
string text, params string[] subItems)
{
var item = new ListViewItem(text);
foreach (var subItem in subItems)
{
item.SubItems.Add(subItem);
}
col.Add(item);
}
}
Calling the AddWithTextAndSubItems looks like this:
// can have many sub items as it's string array
myListViewControl.Items.AddWithTextAndSubItems("Text", "Sub Item 1", "Sub Item 2");
Hope this helps!
I think the quickest/neatest way to do this:
For each class have string[] obj.ToListViewItem() method and then do this:
foreach(var item in personList)
{
listView1.Items.Add(new ListViewItem(item.ToListViewItem()));
}
Here is an example definition
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
public DateTime DOB { get; set; }
public uint ID { get; set; }
public string[] ToListViewItem()
{
return new string[] {
ID.ToString("000000"),
Name,
Address,
DOB.ToShortDateString()
};
}
}
As an added bonus you can have a static method that returns ColumnHeader[] list for setting up the listview columns with
listView1.Columns.AddRange(Person.ListViewHeaders());
Create a listview item
ListViewItem item1 = new ListViewItem("sdasdasdasd", 0)
item1.SubItems.Add("asdasdasd")
ListViewItem item = new ListViewItem();
item.Text = "fdfdfd";
item.SubItems.Add ("melp");
listView.Items.Add(item);
add:
.SubItems.Add("asdasdasd");
to the last line of your code so it will look like this in the end.
listView1.Items.Add("sdasdasdasd").SubItems.Add("asdasdasd");
Generally:
ListViewItem item = new ListViewItem("Column1Text")
{ Tag = optionalRefToSourceObject };
item.SubItems.Add("Column2Text");
item.SubItems.Add("Column3Text");
myListView.Items.Add(item);
Great !! It has helped me a lot. I used to do the same using VB6 but now it is completely different.
we should add this
listView1.View = System.Windows.Forms.View.Details;
listView1.GridLines = true;
listView1.FullRowSelect = true;

Categories