#nullable enable using System.Reflection; using System.Text; namespace UICatalog.Scenarios; [ScenarioMetadata ("Class Explorer", "Tree view explorer for classes by namespace based on TreeView.")] [ScenarioCategory ("Controls")] [ScenarioCategory ("TreeView")] public class ClassExplorer : Scenario { private CheckBox? _highlightModelTextOnlyCheckBox; private CheckBox? _showPrivateCheckBox; private TextView? _textView; private TreeView? _treeView; public override void Main () { Application.Init (); Window win = new () { Title = GetName (), BorderStyle = LineStyle.None }; // MenuBar MenuBar menuBar = new (); // Search controls Label lblSearch = new () { Y = Pos.Bottom (menuBar), Title = "Search:" }; TextField tfSearch = new () { Y = Pos.Top (lblSearch), X = Pos.Right (lblSearch) + 1, Width = 20 }; // TreeView _treeView = new () { Y = Pos.Bottom (lblSearch), Width = Dim.Percent (50), Height = Dim.Fill () }; TreeViewTextFilter filter = new (_treeView); _treeView.Filter = filter; tfSearch.TextChanged += (s, e) => { filter.Text = tfSearch.Text; if (_treeView.SelectedObject is { }) { _treeView.EnsureVisible (_treeView.SelectedObject); } }; _treeView.AddObjects (AppDomain.CurrentDomain.GetAssemblies ()); _treeView.AspectGetter = GetRepresentation; _treeView.TreeBuilder = new DelegateTreeBuilder (ChildGetter, CanExpand); _treeView.SelectionChanged += TreeView_SelectionChanged; // TextView for details _textView = new () { X = Pos.Right (_treeView), Y = Pos.Top (_treeView), Width = Dim.Fill (), Height = Dim.Fill (), ReadOnly = true, }; // Menu setup _showPrivateCheckBox = new () { Title = "_Include Private" }; _showPrivateCheckBox.CheckedStateChanged += (s, e) => ShowPrivate (); _highlightModelTextOnlyCheckBox = new () { Title = "_Highlight Model Text Only" }; _highlightModelTextOnlyCheckBox.CheckedStateChanged += (s, e) => OnCheckHighlightModelTextOnly (); menuBar.Add ( new MenuBarItem ( "_File", [ new MenuItem { Title = "_Quit", Action = Quit } ] ) ); menuBar.Add ( new MenuBarItem ( "_View", [ new MenuItem { CommandView = _showPrivateCheckBox }, new MenuItem { Title = "_Expand All", Action = () => _treeView?.ExpandAll () }, new MenuItem { Title = "_Collapse All", Action = () => _treeView?.CollapseAll () } ] ) ); menuBar.Add ( new MenuBarItem ( "_Style", [ new MenuItem { CommandView = _highlightModelTextOnlyCheckBox } ] ) ); // Add views in order of visual appearance win.Add (menuBar, lblSearch, tfSearch, _treeView, _textView); Application.Run (win); win.Dispose (); Application.Shutdown (); } private bool CanExpand (object arg) => arg is Assembly or Type or ShowForType; private IEnumerable ChildGetter (object arg) { try { return arg switch { Assembly assembly => assembly.GetTypes (), Type type => Enum.GetValues (typeof (Showable)) .Cast () .Select (v => new ShowForType (v, type)), ShowForType show => show.ToShow switch { Showable.Properties => show.Type.GetProperties (GetFlags ()), Showable.Constructors => show.Type.GetConstructors (GetFlags ()), Showable.Events => show.Type.GetEvents (GetFlags ()), Showable.Fields => show.Type.GetFields (GetFlags ()), Showable.Methods => show.Type.GetMethods (GetFlags ()), _ => Enumerable.Empty () }, _ => Enumerable.Empty () }; } catch (Exception) { return Enumerable.Empty (); } } private BindingFlags GetFlags () => _showPrivateCheckBox?.CheckedState == CheckState.Checked ? BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic : BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public; private string GetRepresentation (object model) { try { return model switch { Assembly assembly => assembly.GetName ().Name ?? string.Empty, PropertyInfo propertyInfo => propertyInfo.Name, FieldInfo fieldInfo => fieldInfo.Name, EventInfo eventInfo => eventInfo.Name, _ => model.ToString () ?? string.Empty }; } catch (Exception ex) { return ex.Message; } } private void OnCheckHighlightModelTextOnly () { if (_treeView is null) { return; } _treeView.Style.HighlightModelTextOnly = _highlightModelTextOnlyCheckBox?.CheckedState == CheckState.Checked; _treeView.SetNeedsDraw (); } private void Quit () { Application.RequestStop (); } private void ShowPrivate () { _treeView?.RebuildTree (); _treeView?.SetFocus (); } private void TreeView_SelectionChanged (object? sender, SelectionChangedEventArgs e) { if (_treeView is null || _textView is null) { return; } object? val = e.NewValue; object [] all = _treeView.GetAllSelectedObjects ().ToArray (); if (val is null or ShowForType) { return; } try { if (all.Length > 1) { _textView.Text = $"{all.Length} Objects"; } else { StringBuilder sb = new (); sb.AppendLine (e.NewValue?.GetType ().Name ?? string.Empty); switch (val) { case Assembly assembly: sb.AppendLine ($"Location:{assembly.Location}"); sb.AppendLine ($"FullName:{assembly.FullName}"); break; case PropertyInfo propertyInfo: sb.AppendLine ($"Name:{propertyInfo.Name}"); sb.AppendLine ($"Type:{propertyInfo.PropertyType}"); sb.AppendLine ($"CanWrite:{propertyInfo.CanWrite}"); sb.AppendLine ($"CanRead:{propertyInfo.CanRead}"); break; case FieldInfo fieldInfo: sb.AppendLine ($"Name:{fieldInfo.Name}"); sb.AppendLine ($"Type:{fieldInfo.FieldType}"); break; case EventInfo eventInfo: sb.AppendLine ($"Name:{eventInfo.Name}"); sb.AppendLine ("Parameters:"); if (eventInfo.EventHandlerType?.GetMethod ("Invoke") is { } invokeMethod) { foreach (ParameterInfo parameter in invokeMethod.GetParameters ()) { sb.AppendLine ($" {parameter.ParameterType} {parameter.Name}"); } } break; case MethodInfo methodInfo: sb.AppendLine ($"Name:{methodInfo.Name}"); sb.AppendLine ($"IsPublic:{methodInfo.IsPublic}"); sb.AppendLine ($"IsStatic:{methodInfo.IsStatic}"); sb.AppendLine ($"Parameters:{(methodInfo.GetParameters ().Length > 0 ? string.Empty : "None")}"); foreach (ParameterInfo parameter in methodInfo.GetParameters ()) { sb.AppendLine ($" {parameter.ParameterType} {parameter.Name}"); } break; case ConstructorInfo constructorInfo: sb.AppendLine ($"Name:{constructorInfo.Name}"); sb.AppendLine ($"Parameters:{(constructorInfo.GetParameters ().Length > 0 ? string.Empty : "None")}"); foreach (ParameterInfo parameter in constructorInfo.GetParameters ()) { sb.AppendLine ($" {parameter.ParameterType} {parameter.Name}"); } break; } _textView.Text = sb.ToString ().Replace ("\r\n", "\n"); } } catch (Exception ex) { _textView.Text = ex.Message; } _textView.SetNeedsDraw (); } private enum Showable { Properties, Fields, Events, Constructors, Methods } private sealed class ShowForType { public ShowForType (Showable toShow, Type type) { ToShow = toShow; Type = type; } public Showable ToShow { get; } public Type Type { get; } public override bool Equals (object? obj) => obj is ShowForType type && EqualityComparer.Default.Equals (Type, type.Type) && ToShow == type.ToShow; public override int GetHashCode () => HashCode.Combine (Type, ToShow); public override string ToString () => ToShow.ToString (); } }