我有一個 UserControl,它有幾個通過 VS Designer 添加的 ContextMenuStrips。它們在設計時沒有分配給任何控制元件,因為它們被動態分配給一個背景關系敏感的“下拉”按鈕。我有一個類,它遍歷控制元件中的所有控制元件以主題這些控制元件(即暗模式)。代碼:
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。通過閱讀,我了解到這些不是控制元件,而是組件。我通過以下方式嘗試了一種建議的解決方案:
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
但是我在運行時遇到錯誤:
System.MissingMemberException: 'Public member 'components' on type 'ObjectSelector' not found.'
ObjectSelector 是用戶控制元件。
主題類被許多其他物件(表單、用戶控制元件)使用,因此很難為這個用戶控制元件擁有一個特定的屬性。如何獲取 UserControl 上所有 ContextMenuStrips 的串列?
uj5u.com熱心網友回復:
當您使用設計器并將組件拖放到表單上時,設計器會在表單中創建一個components私有成員欄位。要獲得該成員,您需要依靠反射。
在發布代碼之前,我想強調以下幾點:
- 不斷變化的主題為正道
ContextMenuStrip,ToolStrip,MenuStrip并且StatusStrip被分配為主題的渲染器ToolStripManager.Renderer。 - 所有控制元件的主題管理器的另一個想法是,創建一個擴展器提供程式,它在設計時檢測所有控制元件和組件并分配它們的屬性或處理它們的事件以更改它們的主題。
- 當您在運行時獲取所有控制元件和組件時,結果中可能會有一些不需要的控制元件和組件;例如屬性網格的工具條或數字 updown 的 updown 按鈕。
獲取控制元件的所有后代組件(遞回)
無論如何,我將發布一個用于學習目的的答案,向您展示如何獲取控制元件及其子控制元件上所有組件的串列。為此,我將創建一個擴展方法,您可以像這樣使用它:
var ctxMenuStrips = this.FindForm().AllComponents().OfTypeOf<ContextMenuStrip>();
這是擴展方法的代碼:
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;
}
}
}
uj5u.com熱心網友回復:
注意:完全不同的方法,所以我將其作為另一個答案發布。對某些用戶來說可能更有趣;但是,這也是一種hacky方式。
另一種解決方案依賴于components控制元件的私有成員以遞回方式獲取所有組件,但是如果您只專注于獲取 ToolStrip 及其所有后代,這里是另一種選擇。
在應用程式中獲取所有 ToolStrip、ContextMenuStrip、MenuStrip 和 StatusStrip
該ToolStripManager有一個內部屬性,ToolStrips,這使所有的ToolStrip實體(包括的ToolStrip,MenuStrip中,的ContextMenuStrip,StatusStrip中),你必須在你的應用提供參考。實際上,當您創建這些組件的實體時,它們會將自己添加到工具條管理器的工具條集合中。您可以使用該屬性使用反射獲取所有工具條、背景關系選單條、選單條和狀態條。
這是代碼:
public static IEnumerable<ToolStrip> ToolStrips()
{
var toolStrips = (typeof(ToolStripManager).GetProperty("ToolStrips",
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.NonPublic)
.GetValue(null, null) as System.Collections.IList);
for (int i = 0; i < toolStrips.Count; i )
yield return toolStrips[i] as ToolStrip;
}
并將其限制為背景關系選單條:
var ctxMenuStrips = ToolStrips().OfTypeOf<ContextMenuStrip>();
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/407598.html
標籤:
