How to remove last children from stack panel in WPF? - c#

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.

Related

Can if statements be combined with a variable assignment using pattern matching?

Example of the code that I am talking about:
if (sender is Panel p)
{
if (p.Enabled == false)
{
AMButton.Checked = false;
PMButton.Checked = false;
currentSelectedTime = null;
}
}
Is it possible to "do something more" with the variable p once its been cast in the first if statement thus combining the two statements?
Something such as if(sender is Panel p.Enabled). Combining the two if
statements into one line like that. Does that make sense?
if(sender is Panel p && p.Enabled)
or to get real ugly
if(sender is Panel p && (p.Enabled = somethingElse) == ((someInt = anotherInt) == 5))
The accepted answer of
if (sender is Panel p && p.Enabled)
is correct and works right now.
In C# 8, pattern matching will (probably) be extended to allow property matching:
if (sender is Panel { Enabled: true } p)
This looks a little alien right now, but it's likely to be more and more idiomatic, particularly when matching multiple properties. The recursive patterns can be used to introduce more pattern variables too, and you don't need a pattern variable for the "outer" pattern. For example, suppose we only needed the Tag property from the panel, we could use:
if (sender is Panel { Enabled: true, Tag: var tag })
{
// Use tag in here
}

Checking if treeview contains an item

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.

Migradoc & nested paragraphs

I am using Ben Foster's Migradoc extensions to format a PDF document using Markdown syntax.
I am running into an issue when using headers or sub-lists (<hx> or <li> elements) within a list (a null reference exception is thrown). The issue is detailed here.
The root cause of the problem is that Migradoc does not support nested paragraphs.
Are there any possible workarounds to this issue?
You ask "Are there any possible workarounds to this issue?"
MigraDoc is able to create PDF and RTF. Does RTF (Word) support nested paragraphs?
Probably not. I think this is not a MigraDoc issue.
Nested lists are possible in MigraDoc, but may require changes in the extensions. IIRC there are limitations with respect to nesting when numbered lists are involved.
IMHO nested paragraphs do not make sense. MigraDoc supports AddFormattedText that allows to use different formats in a single paragraph. This may require changes to the extensions and/or the input given to the extensions.
Hey I've been using Ben Foster's Migradoc extensions as well and had this same problem. This may not be perfect, but it worked well enough for me... Modify your HtmlConverter.cs and do the following:
First, add a global variable:
private int _nestedListLevel;
Next, add 2 new node handlers to the AddDefaultNodeHandlers() method:
nodeHandlers.Add("ul", (node, parent) =>
{
if (parent is Paragraph)
{
_nestedListLevel++;
return parent.Section;
}
_nestedListLevel = 0;
return parent;
});
nodeHandlers.Add("ol", (node, parent) =>
{
if (parent is Paragraph)
{
_nestedListLevel++;
return parent.Section;
}
_nestedListLevel = 0;
return parent;
});
Finally, change the "li" node handler to the following... NOTE, this removes some of the styling work that he did, but it made things less complicated for me and works just fine.. you can re-add that stuff if you want.
nodeHandlers.Add("li", (node, parent) =>
{
var listStyle = node.ParentNode.Name == "ul"
? "UnorderedList"
: "OrderedList";
var section = (Section)parent;
var isFirst = node.ParentNode.Elements("li").First() == node;
var isLast = node.ParentNode.Elements("li").Last() == node;
var listItem = section.AddParagraph().SetStyle(listStyle);
if (listStyle == "UnorderedList")
{
listItem.Format.ListInfo.ListType = _nestedListLevel%2 == 1 ? ListType.BulletList2 : ListType.BulletList1;
}
else
{
listItem.Format.ListInfo.ListType = _nestedListLevel % 2 == 1 ? ListType.NumberList2 : ListType.NumberList1;
}
if (_nestedListLevel > 0)
{
listItem.Format.LeftIndent = String.Format(CultureInfo.InvariantCulture, "{0}in", _nestedListLevel*.75);
}
// disable continuation if this is the first list item
listItem.Format.ListInfo.ContinuePreviousList = !isFirst;
if (isLast)
_nestedListLevel--;
return listItem;
});

How to get all Windows Form Elements in a list

I have a windows form application.
Windows form consist of several elements. I can reach each of them by their name.
(ex: textbox1.Text)
Can I get all of form element in a collection?
You can use the method below to traverse a tree and get all of the child controls (at all depths) below any control.
public static IEnumerable<Control> GetAllControls(Control root)
{
var stack = new Stack<Control>();
stack.Push(root);
while (stack.Any())
{
var next = stack.Pop();
foreach (Control child in next.Controls)
stack.Push(child);
yield return next;
}
}
You can then pass in the form as the root to get all of the controls in that form in a single sequence. Use ToList if you want them all in a List instead.
If you want to filter out only the controls of a particular type, use OfType:
var textboxes = GetAllControls(someForm).OfTYpe<Textbox>();
Use this.Controls (or more formally: Control.Controls)
To get all TextBox controls, use this:
this.Controls.OfType<Control>().Where(x => x is TextBox);
This will only get top level items. If you need to go deeper (cue inception), you need to do some recursion.
Try this.Controls in the code behind file and should give you a list of all the controls.

Visual Tree - Find a label (anywhere on the window) where content equals

I have many labels as children of many different stack panels which are all children of a list box, and I need to reference one of these labels were the Content.toString() == "criteria". In other words, traversing the visual tree in WPF would be a ball ache because there are many parent/child methods to run. Is there a way of finding one of these labels on my window without it having a name and assuming I don't know how far 'down' it is in the tree? Maybe there's an item collection of everything in a window (without heirarchy) that I can run some LINQ against??
If you're wondering why I don't have a name for the labels - it's because they are generated by a data template.
Thanks a lot,
Dan
Seems like what you're looking for: Find DataTemplate-Generated Elements
I made a slight change to the code that #anatoliiG linked in order to return all the child controls of the specified type (instead of the first one):
private IEnumerable<childItem> FindVisualChildren<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
yield return (childItem)child;
foreach (var childOfChild in FindVisualChildren<childItem>(child))
yield return childOfChild;
}
}
With this function you could do something like this:
var criteriaLabels =
from cl in FindVisualChildren<Label>(myListBox)
where cl.Content.ToString() == "criteria"
select cl;
foreach (var criteriaLabel in criteriaLabels)
{
// do stuff...
}
i think this code might be usefull for you:
foreach (Control control in this.Controls)
{
if (control.GetType() == typeof(Label))
if (control.Text == "yourText")
{
// do your stuff
}
}
i used This question as my base
I don't know whether this will help or not:
If you are looking for a specific label in each stack panel in the listBox, then you could just look for that specific label with its specific name and compare the content.

Categories