using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Windows.Forms; namespace Inspectron.Settings.Windows.Configuration; public partial class OptionsWindow : Form { private Dictionary> settingsByCategory; private IControlFactory controlFactory; public OptionsWindow(IControlFactory controlFactory) { this.controlFactory = controlFactory; settingsByCategory = new Dictionary>(); InitializeComponent(); this.treeViewCategories.AfterSelect += new TreeViewEventHandler(this.treeViewCategories_AfterSelect); this.buttonOK.Click += new EventHandler(this.buttonOK_Click); this.buttonCancel.Click += new EventHandler(this.buttonCancel_Click); } public void LoadFromSettings(InspectronSettings inspectronSettings) { // UserSettings is a Tree with folders (string) and UserSettingsInfo nodes. // Traverse the tree to find all UserSettingsInfo nodes and their PropertyDescriptors. void Traverse(object nodeObj, string path) { var node = nodeObj as dynamic; // Tree object value = node.Value; if (value is string folderName) { // Folder node, append to path and traverse children string newPath = string.IsNullOrEmpty(path) ? folderName : $"{path}/{folderName}"; foreach (var child in node.Children) Traverse(child, newPath); } else if (value is Inspectron.Settings.InspectronSettings.UserSettingsInfo info) { // Leaf node: user settings group string groupName = info.Name; string groupPath = string.IsNullOrEmpty(path) ? groupName : $"{path}/{groupName}"; foreach (var pd in info.Settings) { // Try to get owner from BoundPropertyDescriptor, else skip object owner = null; string description = pd.Description; if (pd is Inspectron.Settings.BoundPropertyDescriptor bpd) { owner = bpd.Owner; if (string.IsNullOrEmpty(description)) description = bpd.DisplayName; } else { // If not a BoundPropertyDescriptor, cannot get owner, skip continue; } RegisterUserSetting(owner, bpd.PropertyInfo.Name, groupPath, description); } } } Traverse(inspectronSettings.UserSettings.Root, ""); } public void RegisterUserSetting(object owner, string propertyName, string treePath, string description = null) { // Get the PropertyInfo from owner and propertyName var property = owner.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); if (property == null) throw new ArgumentException($"Property '{propertyName}' not found on owner type."); if (string.IsNullOrEmpty(description)) description = propertyName; // Create an OptionSetting instance var setting = new OptionSetting { Owner = owner, Property = property, Description = description, TreePath = treePath, Value = property.GetValue(owner) }; // Add to settingsByCategory if (!settingsByCategory.TryGetValue(treePath, out var settingsList)) { settingsList = new List(); settingsByCategory[treePath] = settingsList; } settingsList.Add(setting); // Add nodes to treeViewCategories AddTreeNodes(treeViewCategories, treePath); } private void AddTreeNodes(TreeView treeView, string treePath) { var parts = treePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); TreeNodeCollection nodes = treeView.Nodes; foreach (var part in parts) { var node = Enumerable.Cast(nodes).FirstOrDefault(n => n.Text == part); if (node == null) { node = new TreeNode(part); nodes.Add(node); } nodes = node.Nodes; } } private void treeViewCategories_AfterSelect(object sender, TreeViewEventArgs e) { // Display the settings for the selected category string selectedPath = GetFullPath(e.Node); DisplaySettings(selectedPath); } private string GetFullPath(TreeNode node) { if (node.Parent == null) return node.Text; else return GetFullPath(node.Parent) + "/" + node.Text; } private void DisplaySettings(string treePath) { flowLayoutPanelSettings.Controls.Clear(); if (settingsByCategory.TryGetValue(treePath, out var settingsList)) { foreach (var setting in settingsList) { var control = controlFactory.CreateControl( setting.Property.Name, setting.Description, setting.Property, setting.Value, (newValue) => { setting.Value = newValue; }, this); flowLayoutPanelSettings.Controls.Add(control); } } } private void buttonOK_Click(object sender, EventArgs e) { // Update the owner properties with the values foreach (var settingsList in settingsByCategory.Values) { foreach (var setting in settingsList) { setting.Property.SetValue(setting.Owner, setting.Value); } } this.DialogResult = DialogResult.OK; this.Close(); } private void buttonCancel_Click(object sender, EventArgs e) { this.DialogResult = DialogResult.Cancel; this.Close(); } }