i have 2 List that i want to put into my Listbox
the first List contain names and the second contain numbers
my problem is that some of the names long so the numbers cannot a display in the same line
how can i put in in appropriate way ?
listBox.Items.Add("Name" + "\t\t\t" + "Number");
for (int i = 0; i < lists.Count; i++)
{
listBox.Items.Add(lists._namesList[i] + "\t\t\t" + lists._numbersList[i]);
}
Update here is what I tried with a ListView
listViewProtocols.View = View.Details;
listViewProtocols.Columns.Add("Name");
listViewProtocols.Columns.Add("Number");
for (int i = 0; i < lists._protocolsList.Count; i++)
{
listViewProtocols.Items.Add(new ListViewItem{ lists._nameList[i], lists._numbersList[i].ToString()});
}
Consider using a ListView component, with Details style. As #Yuck mentioned in the comments it will give you the effect you need.
It is a bit akward to populate from 2 separate lists but it is doable with the code below:
listView1.View=View.Details;
listView1.Columns.Add("Name");
listView1.Columns.Add("Number");
string[] names= { "Abraham", "Buster", "Charlie" };
int[] numbers= { 1018001, 1027400, 1028405 };
for(int i=0; i<names.Length; i++)
{
listView1.Items.Add(
new ListViewItem(new string[] {
names[i], numbers[i].ToString() }));
}
I would strongly recommend doing an array of structures instead of separate lists like this:
public struct Record
{
public string name;
public int number;
public string[] ToStringArray()
{
return new string[] {
name,
number.ToString() };
}
}
and used like this:
listView1.View=View.Details;
listView1.Columns.Add("Name");
listView1.Columns.Add("Number");
Record[] list=new Record[] {
new Record() { name="Abraham", number=1018001 },
new Record() { name="Buster", number=1027400 },
new Record() { name="Charlie", number=1028405 }
};
for(int i=0; i<list.Length; i++)
{
listView1.Items.Add(
new ListViewItem(list[i].ToStringArray()));
}
There are couple of options I can think of:
Make the listbox wider so that it can accomodate longer text or add a horizontal scrollbar to it.
Constrain the max length of names to, let's say, 20 chars and replace extra characters with ....
Probably the best solution is to use grid instead of listbox - you need to display two columns of data, which is exactly the grid is for.
Related
I have a pivot table with a datafield sourced from a single column "Animals" of data in another sheet. This column contains values that I know in advance, let's say these are up to 6 animals : "dog", "cat", "monkey", "fox", "mouse", "sheep" (but some of them could not be present).
And I want the pivot table to report the count of each kind of animal.
//data fields
var field = pivotTable.DataFields.Add(pivotTable.Fields["Animals"]);
field.Function = DataFieldFunctions.Count;
This works well however I would like to always have the animals displayed in the pivot table in a custom fixed order, for example "dog" should always be the fist reported column, then "cat","fox" and "mouse". This can be done from Excel by manually reordering the columns but I fail to do it within EPPlus.
I came with this piece of code which is not working...
private static void ReorderColumns(ExcelPivotTable pivotTable)
{
string[] customOrder = { "dog", "cat", "monkey", "fox", "mouse", "sheep" };
var newIndex = 0;
var diffStatusField = pivotTable.DataFields.First().Field;
diffStatusField.Items.Refresh();
foreach (var label in customOrder)
{
for (int i = newIndex; i < diffStatusField.Items.Count; ++i)
{
if (diffStatusField.Items[i].Value as string == label)
{
if (i != newIndex)
{
Swap(diffStatusField.Items, i, newIndex);
++newIndex;
}
else
{
++newIndex;
break;
}
}
}
}
}
This is not working because I cannot write the Swap method. The API doesn't allow Items mutability, the setter is private.
I also tried to write it in VBA which kind of works out of the EPPlus stuff but I fail to bind the VBA and EPPlus together, it looks like I cannot call VBA code from EPPlus. All I can do is write the VBA code but not run it.
I have also tried to use the AutoSort method with the Conditions without success.
It seems I may use the xml directly but don't know where to start.
Edit : I tried to write the xml directly, I came with this :
private static void ReorderColumns(ExcelPivotTable pivotTable)
{
// Reorder the columns
string[] customOrder = { "dog", "cat", "monkey", "fox", "mouse", "sheep" };
var newIndex = 0;
var diffStatusField = pivotTable.DataFields.First().Field;
diffStatusField.Items.Refresh();
var pivotTableXml = pivotTable.PivotTableXml;
var nsManager = new XmlNamespaceManager(pivotTableXml.NameTable);
nsManager.AddNamespace("d", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
nsManager.AddNamespace("x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
var topNode = pivotTableXml.DocumentElement;
var nodes = topNode.SelectNodes("d:pivotFields/d:pivotField[#axis=\"axisCol\"]/d:items/d:item", nsManager);
foreach (var label in customOrder)
{
for (int i = newIndex; i < diffStatusField.Items.Count; ++i)
{
if (diffStatusField.Items[i].Value as string == label)
{
if (i != newIndex)
{
Swap(nodes, i, newIndex);
++newIndex;
}
else
{
++newIndex;
break;
}
}
}
}
}
private static void Swap(XmlNodeList collection, int index1, int index2)
{
var tmp = collection[index1].Attributes["x"].Value;
((XmlElement)collection[index1]).SetAttribute("x", collection[index2].Attributes["x"].Value);
((XmlElement)collection[index2]).SetAttribute("x", tmp);
}
It's not working either as I did not find the way to make EPPlus use the new xml.
I have the following code that successfully splits filepaths into the constituent folders and filename:
var allfiles = FileLister.GetListOfFiles(_path, "*", SearchOption.AllDirectories).ToList();
List<string[]> n = new List<string[]>();
foreach (var line in allfiles)
{
var str = line.Split(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
n.Add(str);
}
The result (n) is a two dimensional array that looks like this:
Given a "node" position e.g n[0] as seen in the image, I need to transfer the data in n0 to n[0][6] to a winform that has five listboxes as shown:
So my final desired result is that listbox1 will have all the data in n0, n1, n2 and so on. Listbox two will have all the data in n[0][3], n1[3], n2[3] and so on..
Im very new to C# and just dont know how to code this. I would appreciate some help please or even suggestions on an alternative way to do this.
cheers
Here's some sample code to point you in the right direction. Agree with Taw's comments regarding having enough listboxes depending on the depth of your filesystem. This example assumes that you don't have a folder structure that goes deeper than 4 levels:
public partial class Form1 : Form
{
// list of ListBoxes - makes it easy to work out which one to add filepath item to
List<ListBox> boxes = new List<ListBox>();
public Form1()
{
InitializeComponent();
boxes.Add(this.listBox1);
boxes.Add(this.listBox2);
boxes.Add(this.listBox3);
boxes.Add(this.listBox4);
// populate the ListBoxes
populateLists();
}
public void populateLists()
{
// simulate getting data from filesystem
List<string[]> n = new List<string[]>();
n.Add(new string[] { "C:", "foo1", "bar1", "test1.txt" });
n.Add(new string[] { "D:", "foo2", "bar2", "test2.txt" });
n.Add(new string[] { "E:", "foo3", "bar3", "test3.txt" });
n.Add(new string[] { "F:", "foo4", "bar4", "test4.txt" });
n.Add(new string[] { "G:", "foo5", "bar5", "test5.txt" });
// loop through list items
for (var i = 0; i < n.Count; i++)
{
// loop through arrays for each list item
for (var j = 0; j < n[i].Length; j++)
{
boxes[j].Items.Add(n[i][j]);
}
}
}
}
Output:
I'm very new to programming so apologies if this is a very obvious question. Ive searched online but not found an answer that quite fits yet.
I am writing a programme that interprets bytes from an index within a filestream. Once they have been converted into human readable dates/strings/ints etc I wanted to use a Winform to display the results in columns. Currently I using a listbox and just dispalying each entry seperated by columns but this feels lile a very clunky way of doing it.
Can someone please suggest how I might go about placing the results into a display that uses columns?
It's better to use a ListView than a ListBox in your case. Here's an example showing all words in a string in separate columns in a ListView:
Make sure following property is set to your ListView (here the Name is ColumnsListView):
ColumnsListView.View = View.Details;
This method takes a string, splits it by space and adds a column for each of the values:
private void SetListView(string input)
{
var values = input.Split(' ');
ColumnsListView.Columns.Add("Column1");
var item = new ListViewItem(values[0]);
for (var i = 1; i < values.Length; i++)
{
ColumnsListView.Columns.Add("Column" + (i+1));
item.SubItems.Add(new ListViewItem.ListViewSubItem { Text = values[i] });
}
ColumnsListView.Items.Add(item);
}
This can be done differently when using LinQ's Skip() method to add the item with subitems:
private void SetListView(string input)
{
var values = input.Split(' ');
for (var i = 0; i < values.Length; i++)
ColumnsListView.Columns.Add("Column" + (i + 1));
var item = new ListViewItem(values[0]);
item.SubItems.AddRange(values.Skip(1).ToArray());
ColumnsListView.Items.Add(item);
}
Update:
Here's an example in case you want to use a DataGridView:
private void SetDataGridView(string input)
{
var values = input.Split(' ');
for (var i = 0; i < values.Length; i++)
ColumnsDataGridView.Columns.Add("Column" + (i + 1), "Column" + (i + 1));
ColumnsDataGridView.Rows.Add(values);
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Delete row of 2D string array in C#
i have a 2d string array, I want to delete a specified row from the array.
string[] a = new string[] { "a", "b" }; //dummy string array
int deleteIndex = 1; //we want to "delete" element in position 1 of string
a = a.ToList().Where(i => !a.ElementAt(deleteIndex).Equals(i)).ToArray();
dirty but gives the expected result (foreach through the array to test it)
EDIT missed the "2d array" detail, here is the right code for the job
string[][] a = new string[][] {
new string[] { "a", "b" } /*1st row*/,
new string[] { "c", "d" } /*2nd row*/,
new string[] { "e", "f" } /*3rd row*/
};
int rowToRemove = 1; //we want to get rid of row {"c","d"}
//a = a.ToList().Where(i => !i.Equals(a.ElementAt(rowToRemove))).ToArray(); //a now has 2 rows, 1st and 3rd only.
a = a.Where((el, i) => i != rowToRemove).ToArray(); // even better way to do it maybe
code updated
As has been said above you cant remove from an array.
If you are going to need to remove rows quite often maybe change from using a 2d array to a list containing an array of string. This way you can make use of the remove methods that list implements.
Ok so I said you can't "delete" them. That's still true. You'll have to create a new array instance with enough space for the items you want to keep and copy them over.
If this is a jagged array, using LINQ here could simplify this.
string[][] arr2d =
{
new[] { "foo" },
new[] { "bar", "baz" },
new[] { "qux" },
};
// to remove the second row (index 1)
int rowToRemove = 1;
string[][] newArr2d = arr2d
.Where((arr, index) => index != rowToRemove)
.ToArray();
// to remove multiple rows (by index)
HashSet<int> rowsToRemove = new HashSet<int> { 0, 2 };
string[][] newArr2d = arr2d
.Where((arr, index) => !rowsToRemove.Contains(index))
.ToArray();
You could use other LINQ methods to remove ranges of rows easier (e.g., Skip(), Take(), TakeWhile(), etc.).
If this is a true two-dimensional (or other multi-dimensional) array, you won't be able to use LINQ here and will have to do it by hand and it gets more involved. This still applies to the jagged array as well.
string[,] arr2d =
{
{ "foo", null },
{ "bar", "baz" },
{ "qux", null },
};
// to remove the second row (index 1)
int rowToRemove = 1;
int rowsToKeep = arr2d.GetLength(0) - 1;
string[,] newArr2d = new string[rowsToKeep, arr2d.GetLength(1)];
int currentRow = 0;
for (int i = 0; i < arr2d.GetLength(0); i++)
{
if (i != rowToRemove)
{
for (int j = 0; j < arr2d.GetLength(1); j++)
{
newArr2d[currentRow, j] = arr2d[i, j];
}
currentRow++;
}
}
// to remove multiple rows (by index)
HashSet<int> rowsToRemove = new HashSet<int> { 0, 2 };
int rowsToKeep = arr2d.GetLength(0) - rowsToRemove.Count;
string[,] newArr2d = new string[rowsToKeep, arr2d.GetLength(1)];
int currentRow = 0;
for (int i = 0; i < arr2d.GetLength(0); i++)
{
if (!rowsToRemove.Contains(i))
{
for (int j = 0; j < arr2d.GetLength(1); j++)
{
newArr2d[currentRow, j] = arr2d[i, j];
}
currentRow++;
}
}
Instead of array you can use List or ArrayList class. Using it you can dynamically add element and remove based on your requirement. Array is fixed in size, which can not be manipulated dynamically.
The best way is to work with a List<Type>! The items are ordered in the way the are added to the list and each of them can be deleted.
Like this:
var items = new List<string>;
items.Add("One");
items.Add("Two");
items.RemoveAt(1);
I want to remove the element form the array. Actually I don't know the the index of the element and want to remove through it's value. I have tried a lot but fail. This is the function which i used to add element in the Array
string [] Arr;
int i = 0;
public void AddTOList(string ItemName)
{
Arr[i] = ItemName;
i++;
}
And I want to remove the element by the value. I know the below function is wrong but I want to explain what I want:
public void RemoveFromList(string ItemName)
{
A["Some_String"] = null;
}
Thanks
If you want to remove items by a string key then use a Dictionary
var d = new Dictionary<string, int>();
d.Add("Key1", 3);
int t = d["Key1"];
Or something like that.
Array has a fixed size, which is not suitable for your requirement. Instead you can use List<string>.
List<string> myList = new List<string>();
//add an item
myList.Add("hi");
//remove an item by its value
myList.Remove("hi");
List<string> list = new List<string>(A);
list.Remove(ItemName);
A = list.ToArray();
and #see Array.Resize
and #see Array.IndexOf
You can iterate through every value in array and if found then remove it. Something like this
string[] arr = new string[] { "apple", "ball", "cat", "dog", "elephant", "fan", "goat", "hat" };
string itemToRemove = "fan";
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] == itemToRemove)
{
arr[i]=null;
break;
}
}