Checking if treeview contains an item - c#

This problem seems simple enough. I have a treeview, let's call it MyTreeView, populated with all of the drive letters, so the treeview looks like this:
A:\
C:\
D:\
F:\
How do I check if the treeview contains a specific item? How does the treeview identify its items?
I have created a MessageBox to show MyTreeView.Items.GetItemAt(1), and it identifies item 1 as:
"System.Windows.Controls.TreeViewItem Header:C:\ Items.Count:1"
Try the easiest thing first, which obviously doesn't work:
if (MyTreeView.Items.Contains(#"C:\")
{
MessageBox.Show(#"Tree contains C:\");
}
The next easiest thing would be to try making a TreeViewItem that looks similar to what I want, which also doesn't work:
TreeViewItem myItem = new TreeViewItem();
myItem.Header = #"C:\";
if (MyTreeView.Items.Contains(myItem)
{
MessageBox.Show("Tree contains " + myItem.ToString());
}
Just to make sure I had the fundamental concept right, I tried some circular logic, which actually does work:
var myItem = MyTreeView.Items.GetItemAt(1);
if (MyTreeView.Items.Contains(myItem)
{
MessageBox.Show("Tree contains " + myItem.ToString());
}
Which outputs:
"Tree contains System.Windows.Controls.TreeViewItem Header:C:\ Items.Count:1"
What am I doing wrong? How do I check if my tree contains something like "C:\" ?
edit:
The code for building the tree is this:
(basically a copy and paste from the internet)
foreach (string myString in Directory.GetLogicalDrives())
{
TreeViewItem item = new TreeViewItem();
item.Header = myString;
item.Tag = myString;
item.FontWeight = FontWeights.Normal;
item.Items.Add(dummyNode); // this is (object)dummyNode = null
item.Expanded += new RoutedEventHandler(DWGFolder_Expanded);
item.Selected += new RoutedEventHandler(DWGFolder_Selected);
// the Expanded event is very similar,
// subitem.Header is the folder name (Testing),
// while subitem.Tag is the full path (C:\Testing)
MyTreeView.Items.Add(item);
}
So basically I'm trying to match TreeViewItem objects.

I believe .Contains() would check for the value by reference since it isn't a simple string object. This requires you to iterate through each of the items until you retrieve the item which matches the header.
LINQ Example
if (MyTreeView.Items.Cast<TreeViewItem>().Any(item => item.Header.ToString() == #"C:\"))
{
MessageBox.Show(#"Tree contains C:\");
}

Contains looks for the exact same instance inside the collection. If you don't have the object you want to check already, you can't use Contains.
But you can use some basic LINQ query... Add the LINQ namespace to your class:
using System.Linq;
If your items are indeed just Strings, then use this query (EDIT - Though, in case they're just Strings, Contains should work, since their equality comparers don't behave like those of regular reference types, but compare by value):
if (MyTreeView.Items.Cast<string>().Any(s => s == #"C:\"))
{
// Do stuff
}
If your items are TreeViewItems, you can use this one:
if (MyTreeView.Items.Cast<TreeViewItem>().Any(i => i.Header.ToString() == #"C:\"))
{
// Do stuff
}
But your items could be any class we don't know, or your header binding could change... Without knowing how you're adding the items to the TreeView, it's hard to give you the best alternative.
EDIT - Keep in mind that this will only search in the first level of the tree. If the item you're looking for is placed somewhere deeper, you'll have to do a recursive search. At that point, maybe just keeping the values stored somewhere from the start would be better.

Related

C# How to prevent ListBox to select first item when you unselect the last one

C# How to prevent ListBox in MultiSimple selection mode to select first item automatically, when you unselect the last one selected item in the box - it happens only if listbox represented by my own class objects, and everything is ok when it represented by string objects. Thnx!
It seems like keeping track of the order of the list is the most important part. I would suggest maybe making an array of a struct. You can make this struct contain whatever you want for example:
struct itemList
{
public string itemName;
public int itemIndex;
//include whatever other variables that you need included in here.
}
Also, make sure you place your struct before the namespace. Then, making the array of the struct would look like this:
itemList[] items1 = new itemList[listBoxName.SelectedItems.Count];
All you would have to do then is to add the items to the array before you reorder the listBox
for (int i = 0; i < listBoxName.SelectedItems.Count; i++)
{
items1[i].itemName = listBoxName.SelectedItems[i].ToString();
items1[i].itemIndex = listBoxName.SelectedIndices[i];
}
Thank you very much, but i already use some like this. I don't understand why first item of listBox selected everytime i assign preloaded list as DataSource. I resolve this problem, by making another one temporal List of my object class, which items readed from binary file, and then push them one by one to my original List in foreach cycle by listOfObjects.Add(object) method. I know that every time after code ListOfTags.DataSource = null;
ListOfTags.DataSource = tags;
ListOfTags.DisplayMember = "Name"; if my tags (it is a List) are preloaded even in code (for example if i write code List<Tag> tags = new List<Tag> {new Tag("1"),new Tag("2"), new Tag("3")}; , this takes situation when first item of listbox selected, and starts selects everytime after that when i try do deselect last selected item in listBox.

How to remove last children from stack panel in WPF?

I am adding children to my stackpanel dynamically. What I need is, I want to remove the last children for certain scenario. Is there any option to get last children?
Here is my code:
var row = new somecontrol();
stackpanel.Children.Add(row);
Is there any possible way to remove children.lastOrDefault()?
stackpanel.Children.Last();
Any help would be appreciated. Thanks in advance.
How about:
if(stackpanel.Children.Count != 0)
stackpanel.Children.RemoveAt(stackpanel.Children.Count - 1);
...or if you want to use Linq, just use the OfType<> ExtensionMethod. Then you can do whatever with Linq you wish, like LastOrDefault:
var child = stackpanel.Children.OfType<UIElement>().LastOrDefault();
if(child != null)
stackpanel.Children.Remove(child);
But, the first is probably fastest.
Or you can make your own Extension method, if you want:
class PanelExtensions
{
public static void RemoveLast(this Panel panel)
{
if(panel.Children.Count != 0)
panel.Children.RemoveAt(panel.Children.Count - 1);
}
}
Use like this
stackpanel.Children.RemoveLast();
But Like Xeun mentions an MVVM solution with Bindings would be preferable.

How to check for list in LINQ

I am trying to read a file and process using LINQ.
I have a exclude list where if i encounter certain words in the file, i should omit that line
my code is
string sCodeFile = #"C:\temp\allcode.lst";
List<string> sIgnoreList = new List<string>() { "foo.c", "foo1.c" };
var wordsPerLine = from line in File.ReadAllLines(sCodeFile)
let items = line.Split('\n')
where !line.Contains(sIgnoreList.ToString())
select line;
foreach (var item in wordsPerLine)
{
console.WriteLine(item);
}
My LST file looks like below
\voodoo\foo.c
\voodoo\voodoo.h
\voodoo\std.c
\voodoo\foo1.h
in the end i want only
\voodoo\voodoo.h
\voodoo\std.c
How can i process the ignored list in contains? with my above code i dont get the desired output for sure
can any one help?
regards,
Karthik
Revised my answer. The bug is that you're doing a ToString on the ignore list, which certainly will not work. You must check each item in the list, which can be done using something like this:
where !sIgnoreList.Any(ignore => line.Contains(ignore))
A curiosity: since the above lambda is just passing a value into a method that only take the value as a parameter, you can write this even more compact as a method group like this:
where !sIgnoreList.Any(line.Contains)
Try this.
string sCodeFile = #"C:\temp\allcode.lst";
List<string> sIgnoreList = new List<string>() { "foo.c", "foo1.c" };
var wordsPerLine = File.ReadAllLines(sCodeFile).Where(n =>
{
foreach (var ign in sIgnoreList)
{
if (n.IndexOf(ign) != -1)
return false;
}
return true;
});
It passes the current element (n) to a lambda function, which checks it against every element of the sIgnoreList. Returning false means the element is ignored, true means it's returned.
Change it to:
where !sIgnoreList.Contains(line)
You need to compare each single line and check that it doesn't exist in the ignore list.
That's why the Vladislav's answer did not work.
Here's the working solution:
var result = from line in File.ReadAllLines(codeFile)
where !ignoreList.Any(line.Contains)
select line;
The problem was you didn't want to check for the whole path and messed up words/lines part a bit.

c# linkedlist how to get the the element that is before the last element

i try to implement a redo undo in my windows form application.
i build a linkedlist , every entery of the list is a class that save the state of all the elemnts in the form.
every click on the save button , insert to this list the last state of the form elements.
when the user click on undo button i want to get the entery of the list (one before the last)
and load it.
i dont know what is the simple way to get this one before elemnts from the linked list ?
my code like look like:
public class SaveState {
public int comboBox1;
public int comboBox2;
..........
public SaveState() {
.......
}
}
LinkedList<SaveState> RedoUndo = new LinkedList<SaveState>();
# in save function
var this_state = new SaveState();
this_state = getAllState();
RedoUndo.AddLast(this_state);
# when click undo
var cur_state = new SaveState();
# this lines dont work !!!!!!!!!
int get = RedoUndo.Count - 1;
cur_state = RedoUndo.Find(get);
setAllState(cur_state);
You can get the last node via LinkedList<T>.Last
// list is LinkedList<T> for some T
var last = list.Last;
and the penultimate node via LinkedListNode<T>.Previous
var penultimate = last.Previous; // or list.Last.Previous;
Note that this is a LinkedListNode<T> and you need to use the LinkedListNode<T>.Value property get the underlying instance of T.
Of course, you should take care to check that list is not null, and list.Last is not null (in the case of an empty list), and that list.Last.Previous is not null (in the case of a single-element list).
#Haim, you may want to check out Krill Osenkov's Undo Framework. It makes undo/redo very easy.

Simple Linq to XML Query Doesn't Work

I nominate me for village idiot.
Why doesn't this work:
foreach (XElement clientField in _clientXml.Descendants("row").Descendants())
{
var newFieldName =
from sourceField in _sourceEntries.Descendants("Field")
where (string)sourceField.Attribute("n") == (string)clientField.Attribute("n")
select new
{
FieldName = ((string) sourceField.Attribute("n")),
AcordRef = ((string) sourceField.Attribute("m"))
};
foreach (var element in newFieldName)
{
Console.WriteLine("Field Name: {0}",
element.FieldName, element.AcordRef);
}
}
My source XML files are loaded with XElement.Load(myFileName). In debug, clientField has an attribute n="Policy Number". The first element of _sourceEntries.Descendants("Field") also has an attribute n="Policy Number". Indeed, each element in _clientXml.Descendants("row").Descendants() has a matching row in _sourceEntries.Descendants("Field"). And, I know just enough to know that the select is lazy, so in debug I look at the Console.WriteLine block. No matter what I've tried, newFieldName is an empty set.
Just in case, here's the first element of the client file:
<Column_0 n="Policy Number">ABC000123</Column_0>
And, here's the fist element of the _sourceEntries collection:
<Field n="Policy Number" c="1" l="" s="" cd="" m="1805" f="" />
I know it's going to be something simple, but I just don't see what I'm doing wrong.
Thanks.
Randy
This accomplished what I ultimately needed to do:
foreach (var clientField in _clientXml.Descendants("row").Descendants())
{
foreach (var acordMapRef in
from sourceEntry in _clientTemplate.Descendants("SourceEntries").Descendants("Field")
where (string) clientField.Attribute("n") == (string) sourceEntry.Attribute("n")
from acordMapRef in _clientTemplate.Descendants("Acord").Descendants("Field")
where (string) sourceEntry.Attribute("m") == (string) acordMapRef.Attribute("id")
select acordMapRef)
{
clientField.Attribute("n").Value = (string) acordMapRef.Attribute("n");
}
}
But, it's surely a candidate for ugliest code of the month. One thing I noticed in fooling around is that elements in an XElement tree don't seem to match to XElements in an IEnumerable collection. You might notice in the original code, above, I had an object _sourceEntries. This was a collection derived from _clientTemplate.Descendants("SourcEntries").Descendants("Field"). I would have thought that the two forms were essentially equivalent for my purposes, but apparently not. I'd appreciate somebody commenting on this issue.
Thanks folks!
Try changing:
where (string)sourceField.Attribute("n") == (string)clientField.Attribute("n")
To:
where sourceField.Attribute("n").Value == clientField.Attribute("n").Value

Categories