It took me a while to get to work back at that project. The Link from @Oleg was indeed helpful in that it pointed to the Expander control. The only thing missing was to get into the visual tree and find that element. From then on it was relatively easy to find the missing parts. Here is the code I used in the end. The GetDescendantByType method was copied from somewhere here in Stackoverflow as well. The rest was storing the expanded state in conjunction with a group name (expandedStateStatus is a Dictionary containing those entries).
StackPanel sp = (StackPanel)GetDescendantByType(LvMslInfoTable, typeof(StackPanel));
foreach (var gi in sp.Children.Cast<GroupItem>())
{
var tb = (TextBlock)GetDescendantByType(gi, typeof(TextBlock));
if (tb == null) continue;
Expander exp = (Expander)GetDescendantByType(gi, typeof(Expander));
if (exp == null) continue;
if (!expandedStateStatus.ContainsKey(tb.Text))
{
expandedStateStatus.Add(tb.Text, exp.IsExpanded);
}
}
private static Visual GetDescendantByType(Visual element, Type type)
{
if (element == null) return null;
if (element.GetType() == type) return element;
Visual foundElement = null;
if (element is FrameworkElement frameworkElement)
{
frameworkElement.ApplyTemplate();
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
foundElement = GetDescendantByType(visual, type);
if (foundElement != null)
{
break;
}
}
return foundElement;
}