I have a UserControl which has several ContextMenuStrips add via VS Designer. They are not assigned at design time to any controls, because they are dynamically assigned to one "dropdown" button which is context sensative.I have a Class that iterates through all the controls within a control to theme those controls (i.e. dark mode). The code:
Private ControlList As List(Of Control) = New List(Of Control)()
Private Sub GetAllControls(ByVal container As Control)
For Each c As Control In container.Controls
GetAllControls(c)
ControlList.Add(c)
Next
End Sub
ContextMenuStrips are not detected. From reading, I understand that these are not a Control, but a Component. I tried one suggested solution via:
Private Sub GetAllComponents(container As Object)
For Each co As System.ComponentModel.Component In container.components.Components
If TypeOf co Is ContextMenuStrip Then
ControlList.Add(co)
End If
Next
End Sub
However I get an error at run-time:
System.MissingMemberException: 'Public member 'components' on type 'ObjectSelector' not found.'
ObjectSelector is the UserControl.
The theming Class is used by lots of other objects (forms, usercontrols) so it is difficult to have a specific property for this one UserControl. How can I get a list of all the ContextMenuStrips on a UserControl?
When you use designer and drop a component on the form, the designer creates a components
private member field form the form. To get that member you need to rely on reflection.
Before I post the code I'd like to highlight the following points:
ContextMenuStrip
, ToolStrip
, MenuStrip
and StatusStrip
is assigning a themed renderer to ToolStripManager.Renderer.Get All descendant components of a control (recursively)
Anyways, I'll post an answer for learning purpose to show you how you can get a list of all components on a control and it's children. To so, I'll create an extension method which you can use like this:
var ctxMenuStrips = this.FindForm().AllComponents().OfTypeOf<ContextMenuStrip>();
Here's the code of the extension method:
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
public static class ControlExtensions
{
public static IEnumerable<Component> AllComponents(this Control control)
{
var componentsFields = control.GetType().GetField("components",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
var components = componentsFields?.GetValue(control) as IContainer;
if (components != null)
foreach (Component component in components.Components)
yield return component;
foreach (Control child in control.Controls)
foreach (Component c in child.AllComponents())
yield return c;
}
public static IEnumerable<Control> AllControls(this Control control)
{
foreach (Control c in control.Controls)
{
yield return c;
foreach (Control child in c.AllControls())
yield return child;
}
}
}