I need to populate a TreeView without using SelectedNode property.
This TreeView must contain the items (in most cases - strings) that are in a listbox. These items should be sorted like in a simple binary tree. The root node is the first item. If some of the items is repeated, the count of this item should be increased and the output should be like that ->
-- item 2
| -- private
| - apple
or something like that. In this example, item is the root, apple should be the left child and private - the right.
I found a possible solution here but i have no idea how to do the whole thing :/
Here is my code:
public void populateBaseNodes()
{
int i;
treeView1.Nodes.Clear();
treeView1.BeginUpdate();
for (i = 0; i < L.Count(); i++)
{
if (L[i].level == 0)
{
treeView1.Nodes.Add(L[i].NodeText, L[i].NodeText);
treeView1.Nodes[treeView1.Nodes.Count - 1].Tag = L[i];
}
}
for (i = 0; i < treeView1.Nodes.Count; i++)
populateChilds(treeView1.Nodes[i]);
treeView1.EndUpdate();
treeView1.Refresh();
}
public void populateChilds(TreeNode parentNode)
{
kData parentRed = (kData)parentNode.Tag;
for (int i = parentRed.index + 1; i < L.Count; i++)
{
if (L[i].level == (parentRed.level + 1))
{
parentNode.Nodes.Add(L[i].NodeText, L[i].NodeText);
parentNode.Nodes[parentNode.Nodes.Count - 1].Tag = L[i];
populateChilds(parentNode.Nodes[parentNode.Nodes.Count - 1]);
}
if (L[i].level <= parentRed.level) break;
}
}
And this is my code for the button that will populate the treeview ->
string line;
L = new List<kData>();
for (int i = 0; i < listBox1.Items.Count; i++)
{
line = listBox1.Items[i].ToString();
L.Add(new kData());
L[i].index = i;
L[i].level = i;
ind = line.IndexOf(':');
L[i].NodeText = line.Substring(0, ind);
}
populateBaseNodes();
This is the kData class ->
public class kData
{
public int level;
public int index;
public string NodeText;
};
List<kData> L;
I will appreciate any kind of help :)
Related
I am very new programmer, the user is able to input vales into a ListBox, there is also a option button where the user can sort the numbers in ascending order. However I am also asked to create a option button to unsort back into its original form, however I am not sure how I would do this. I am trying to do this without the use of any containers/arrays. here is my code to sort:
private void sorted()
{
int a = lstHoldValue.Items.Count;
for (int i = 0; i < a - 1; i++)
{
var k = 0;
for (var j = 1; j < a - i; j++)
{
if (Convert.ToInt32(lstHoldValue.Items[j]) < Convert.ToInt32(lstHoldValue.Items[k]))
{
var temp = lstHoldValue.Items[j];
lstHoldValue.Items[j] = lstHoldValue.Items[k];
lstHoldValue.Items[k] = temp;
k = j;
}
else
{
k++;
}
}
}
}
Currently the user is able to input numbers into the ListBox, and I want the ListBox to be sorted by the bubble sort below when a sort checkbutton is clicked. However, it only outputs the index number e.g. 0,1,2,3... I am not allowed to use any array or containers just the items property and parsing and converting.
private void sorted()
{
int a = Convert.ToInt32(lstHoldValue.Items.Count);
int temp;
for (int i = 0; i < a; i++)
{
for (int j = i + 1; j < a; j++)
{
if (Convert.ToInt32(lstHoldValue.Items[i]) >
Convert.ToInt32(lstHoldValue.Items[j]))
{
temp = Convert.ToInt32(lstHoldValue.Items[i]);
(lstHoldValue.Items[i]) = Convert.ToInt32(lstHoldValue.Items[j]);
(lstHoldValue.Items[j]) = temp;
}
}
}
lstHoldValue.Items.Clear();
for (int i = 0; i < a; i++)
{
Convert.ToInt32(lstHoldValue.Items.Add("\t" + i));
}
}
This is more like a Bubble sort algorithm:
private void BubbleSort()
{
int a = lstHoldValue.Items.Count;
for (int i = 0; i < a - 1; i++)
{
var k = 0;
for(var j = 1; j < a - i; j++)
{
if (Convert.ToInt32(lstHoldValue.Items[j]) < Convert.ToInt32(lstHoldValue.Items[k]))
{
var temp = lstHoldValue.Items[j];
lstHoldValue.Items[j] = lstHoldValue.Items[k];
lstHoldValue.Items[k] = temp;
k = j;
}
else
{
k++;
}
}
}
}
It will sort the numbers in the Items collection of your lstHoldValue listBox control
If the item in the ListBox is not an integer, then it is sorted as zero (0).
This sets bubbleUp to true indicating that a swap has been made in the list box. This variable is used to indicate that a swap has/has not been made in the last comparison. Entering the while(bubbleUp) sets bubbleUp to false to indicate that no swaps have been made. Then a loop through each item in the list box to compare adjacent items and swap if needed. If a swap is made, bubbleUp gets set to true indicating that the sort is not finished. bubbleUp only needs to be set once in the for loop to indicate another iteration is necessary. CheckItem is the conversion from string to integer. Hope this helps.
private void sorted()
{
bool bubbleUp = true;
string temp = "";
while (bubbleUp)
{
// bubble up adjacent values
bubbleUp = false;
for (int i = 0; i < _ListBox.Items.Count - 1; i++)
{
if (CheckItem(_ListBox.Items[i].ToString()) > CheckItem(_ListBox.Items[i + 1].ToString()))
{
temp = _ListBox.Items[i].ToString();
_ListBox.Items[i] = _ListBox.Items[i + 1];
_ListBox.Items[i + 1] = temp;
bubbleUp = true;
}
}
}
}
private int CheckItem(string inItem)
{
int value;
if (int.TryParse(inItem, out value))
return value;
return 0;
}
private void button1_Click(object sender, EventArgs e)
{
sorted();
}
There is a movies table. I added films of every customer to List. How can I add these elements of list without array to class that can receive inheritance from List<string>?
int sayici = 0;
for (int i = 0; i < filmler.Count; )
{
List<string> flm = new List<string>();
n = new varliklar.kisi_film_listesi();
for (int j = i + 1; j < (filmler.Count - 1); j++)
{
if (filmler[i]._CustomerID == filmler[j]._CustomerID)
{
flm.Add(filmler[j - 1]._Movie);
sayici++;
}
}
Veri nesneVeri = new Veri();
n._CumtomerID = filmler[i]._CustomerID;
n._movies = flm;
// I WANT TO CHANGE THIS "for" LOOP, I WANT TO ADD WITHOUT ARRAY
for (int a = 0; a < flm.Count; a++)
{
nesneVeri.Add(flm[a]);
}
db.Add(nesneVeri);
i += sayici + 1;
sayici = 0;
}
This is also my Data class below
public class Veri : List<String>
{
public double Destek { get; set; }
public bool Contains(Veri veriler)
{
return (this.Intersect(veriler).Count() == veriler.Count);
}
public Veri Remove(Veri veriler)
{
Veri removed = new Veri();
removed.AddRange(from item in this
where !veriler.Contains(item)
select item);
return (removed);
}
public override string ToString()
{
return ("{" + string.Join(", ", this.ToArray()) + "}" + (this.Destek > 0 ? " (Destek: " + Math.Round(this.Destek, 2) + "%)" : string.Empty));
}
Well this loop:
for (int a = 0; a < flm.Count; a++)
{
nesneVeri.Add(flm[a]);
}
is the same as:
nesneVeri.AddRange(flm);
The List<T>.AddRange function can take any IEnumerable<T>, so it will work with a list or an array. But I'm not sure what the actual issue is.
Because the class Veri inherits from List<string> you can use the AddRange method of the List class.
In your example, you can replace the for loop you want to change with this line of code.
nesneVeri.AddRange(flm)
This is how i'm adding the TreeNodes and Nodes to the treeView1.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace ScrollLabelTest
{
public partial class DisplayResponses : Form
{
private int count;
private List<string> nodesNames = new List<string>();
private List<TreeNode> CurrentNodeMatches = new List<TreeNode>();
public DisplayResponses()
{
InitializeComponent();
label11.Text = "0";
count = 0;
label9.Text = InputLanguage.CurrentInputLanguage.LayoutName;
InputLanguageChanged += DisplayResponses_InputLanguageChanged;
button4.Enabled = false;
addmore();
}
void DisplayResponses_InputLanguageChanged(object sender, InputLanguageChangedEventArgs e)
{
label9.Text = InputLanguage.CurrentInputLanguage.LayoutName;
}
public void addmore()
{
for (int i = 0; i < ListsExtractions.text1.Count; i++)
{
}
for (int i = 0; i < ListsExtractions.responsers.Count; i++)
{
if (ListsExtractions.responsers[i].Count == 0)
{
ListsExtractions.responsers.RemoveAt(i);
}
}
foreach (List<string> l_branch in ListsExtractions.responsers)
{
TreeNode l_node = treeView1.Nodes.Add(l_branch[l_branch.Count - 1]);
for (int l_count = 0; l_count < l_branch.Count - 1; l_count++)
{
l_node.Nodes.Add(l_branch[l_count]);
}
}
}
responsers is a List>
What i see in the treeView1 is this:
Now i have another List
for (int i = 0; i < ListsExtractions.text1.Count; i++)
{
}
It's inside the addmore method
I want to compare each item in text1 to a node text and if they identical add near the node the icon
The icon is in my project resources.
For example in the screenshot i added here if the first node is identical/exist in the text1 add near it on the right the icon fro the resources.
EDIT
This is what i tried to do:
public void addmore()
{
for (int i = 0; i < ListsExtractions.responsers.Count; i++)
{
if (ListsExtractions.responsers[i].Count == 0)
{
ListsExtractions.responsers.RemoveAt(i);
}
}
foreach (List<string> l_branch in ListsExtractions.responsers)
{
TreeNode l_node = treeView1.Nodes.Add(l_branch[l_branch.Count - 1]);
for (int l_count = 0; l_count < l_branch.Count - 1; l_count++)
{
l_node.Nodes.Add(l_branch[l_count]);
}
}
//AddIcons(l_node);
}
And the AddIcons method:
private void AddIcons(TreeNode l_node)
{
for (int i = 0; i < ListsExtractions.text1.Count; i++)
{
for (int x = 0; x < l_node.Nodes.Count; x++)
{
if (l_node.Nodes[x].Text == ListsExtractions.text1[i])
{
//l_node.ImageIndex = 0;
l_node.Nodes[i].ImageIndex = 0;
}
}
}
}
First thing is how do i pass the l_node variable to the AddIcons method ?
Second i tried to move the l_node variable to the top of the form then inside AddIcons it never got inside the comparison:
if (l_node.Nodes[x].Text == ListsExtractions.text1[i])
And i checked some of the items in text1 exist also in the Nodes Text
I added the screenshot before what i want to do is for example if the first top node text == to one of the items in text1 then add icon.
Then move to the next node and compare it to the items in text1
And so on all the nodes only the main nodes not the child nodes.
For example if the first node is:
+-- hello world
And if hello world is in text1 then add the icon to the node hello world
also the format of items in text1 is like this:
In index 0 text: hello world
In index 1 empty: ""
In index 2 text: hello
In index 3 empty: ""
This is how text1 built
EDIT
This is what i tried now:
In the form1 constructor:
InitializeComponent();
il = new ImageList();
il.Images.Add(Properties.Resources.stock_lock);
treeView1.ImageList = il;
label11.Text = "0";
count = 0;
label9.Text = InputLanguage.CurrentInputLanguage.LayoutName;
InputLanguageChanged += DisplayResponses_InputLanguageChanged;
button4.Enabled = false;
addmore();
il is ImageList variable
And the addmore method:
public void addmore()
{
for (int i = 0; i < ListsExtractions.responsers.Count; i++)
{
if (ListsExtractions.responsers[i].Count == 0)
{
ListsExtractions.responsers.RemoveAt(i);
}
}
foreach (List<string> l_branch in ListsExtractions.responsers)
{
TreeNode l_node = treeView1.Nodes.Add(l_branch[l_branch.Count - 1]);
if (ListsExtractions.text1.Contains(l_node.Text)) l_node.ImageIndex = 0;
for (int l_count = 0; l_count < l_branch.Count - 1; l_count++)
{
TreeNode l_subnode = l_node.Nodes.Add(l_branch[l_count]);
if (ListsExtractions.text1.Contains(l_subnode.Text)) l_subnode.ImageIndex = 0;
}
}
}
But what i get is that every node have the icon near him and not only those who exist by text/name in the List text1.
This is what i get:
Not quite sure if that's what you want, but if you want to do the decoration during the creation of the tree you simply need to do it at the right moment, that is while you have the reference to the new node:
treeView1.ImageList = il;
treeView1.ImageIndex= 999;
treeView1.SelectedImageIndex= 999;
foreach (List<string> l_branch in ListsExtractions.responsers)
{
TreeNode l_node = treeView1.Nodes.Add(l_branch[l_branch.Count - 1]);
if (ListsExtractions.Contains (l_node.Text) ) l_node.ImageIndex = 0;
for (int l_count = 0; l_count < l_branch.Count - 1; l_count++)
{
TreeNode l_subnode = l_node.Nodes.Add(l_branch[l_count]);
if (ListsExtractions.Contains (l_subnode.Text) ) l_subnode.ImageIndex = 0;
}
}
I make use of the Contains method of List<T> and I grab a handle to the new subnodes when I create them..No need for the AddIcons method.
Edit: There was an error in the original version: If you activate the ImageList by setting one ImageIndex you need to follow a few rules: All nodes will show the first image (Index 0) in the list as both default SelectedImageIndex and default ImageIndex. Therefore you must either include one blank image in the list, all transparent or in the Tree's BackGroundColor on index position 0. Consequently you must set the decorated nodes to show the Image with index 1, both as SelectedImageIndexand as ImageIndex..
..Or you set the default indices (SelectedImageIndexand the ImageIndex) to a number you don't use in your ImageIndex.
Note the gap in the lines where there is no image set! You can try to patch it by creating a default image that fills the gap..:
< === Here is one that works for me.
Whats the best way to swap two ListView items in C#? I see that the standard ListView doesn't implement such functionality.
--
Best Regards,
Murat
Building upon the KnowDotNet article ref'd by Murat, here's my extension method that is a bit more flexible (it operates on any item, not just the cursel), and bugfixed (BeginUpdate/Endupdate for less flicker, EnsureVisible, and bounds checking).
Doesn't need to be an extension method, but I like them :)
namespace YourApp
{
public static class MyExtensions
{
// Based upon http://www.knowdotnet.com/articles/listviewmoveitem.html
public static void MoveSelectedItem(this System.Windows.Forms.ListView lv, int idx, bool moveUp)
{
// Gotta have >1 item in order to move
if(lv.Items.Count > 1)
{
int offset = 0;
if (idx >= 0)
{
if (moveUp)
{
// ignore moveup of row(0)
offset = -1;
}
else
{
// ignore movedown of last item
if (idx < (lv.Items.Count - 1))
offset = 1;
}
}
if (offset != 0)
{
lv.BeginUpdate();
int selitem = idx + offset;
for (int i = 0; i < lv.Items[idx].SubItems.Count; i++)
{
string cache = lv.Items[selitem].SubItems[i].Text;
lv.Items[selitem].SubItems[i].Text = lv.Items[idx].SubItems[i].Text;
lv.Items[idx].SubItems[i].Text = cache;
}
lv.Focus();
lv.Items[selitem].Selected = true;
lv.EnsureVisible(selitem);
lv.EndUpdate();
}
}
}
}
}
If you use custom ListViewItem, or object you cannot clone object, or stock in string:
enum Direction { UP = -1, DOWN = +1};
void ListViewMove(ListView lv, Direction direction)
{
if (lv.SelectedItems.Count > 0)
{
int selIdx = lv.SelectedItems[0].Index;
ListViewItem tmp = lv.Items[selIdx] ;
if ( ( (selIdx != 0) && direction == Direction.UP ) ||
((selIdx!=lv.Items.Count-1) && (direction == Direction.DOWN)) )
{
lv.Items.RemoveAt(selIdx);
tmp = lv.Items.Insert(selIdx + (int)direction, tmp);
tmp.Selected = true;
}
}
lv.Focus();
}
Both ASP.NET and Winforms ListView have Items property which allows to add or removed items.
I´ve wrote a little sample that should work.
ListViewItem[] copyOfItemsInListView1 = new ListViewItem[listView1.Items.Count];
ListViewItem[] copyOfItemsInListView2 = new ListViewItem[listView2.Items.Count];
listView1.Items.CopyTo(copyOfItemsInListView1, 0);
listView2.Items.CopyTo(copyOfItemsInListView2, 0);
listView1.Items.Clear();
listView2.Items.Clear();
for (int i = 0; i < copyOfItemsInListView2.Length; i++)
{
listView1.Items.Add(copyOfItemsInListView2[i]);
}
for (int i = 0; i < copyOfItemsInListView1.Length; i++)
{
listView2.Items.Add(copyOfItemsInListView1[i]);
}
Clone them:
// move selected item up
int selectedIndex = mListView.SelectedIndices[0];
if (selectedIndex > 0)
{
ListViewItem item1 = (ListViewItem)mListView.Items[selectedIndex - 1].Clone();
ListViewItem item2 = (ListViewItem)mListView.Items[selectedIndex].Clone();
mListView.Items[selectedIndex - 1] = item2;
mListView.Items[selectedIndex] = item1;
mListView.SelectedIndices.Remove(selectedIndex);
mListView.SelectedIndices.Add(selectedIndex - 1);
}