ClassExplorer.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #nullable enable
  2. using System.Reflection;
  3. using System.Text;
  4. namespace UICatalog.Scenarios;
  5. [ScenarioMetadata ("Class Explorer", "Tree view explorer for classes by namespace based on TreeView.")]
  6. [ScenarioCategory ("Controls")]
  7. [ScenarioCategory ("TreeView")]
  8. public class ClassExplorer : Scenario
  9. {
  10. private CheckBox? _highlightModelTextOnlyCheckBox;
  11. private CheckBox? _showPrivateCheckBox;
  12. private TextView? _textView;
  13. private TreeView<object>? _treeView;
  14. public override void Main ()
  15. {
  16. Application.Init ();
  17. Window win = new ()
  18. {
  19. Title = GetName (),
  20. BorderStyle = LineStyle.None
  21. };
  22. // MenuBar
  23. MenuBar menuBar = new ();
  24. // Search controls
  25. Label lblSearch = new ()
  26. {
  27. Y = Pos.Bottom (menuBar),
  28. Title = "Search:"
  29. };
  30. TextField tfSearch = new ()
  31. {
  32. Y = Pos.Top (lblSearch),
  33. X = Pos.Right (lblSearch) + 1,
  34. Width = 20
  35. };
  36. // TreeView
  37. _treeView = new ()
  38. {
  39. Y = Pos.Bottom (lblSearch),
  40. Width = Dim.Percent (50),
  41. Height = Dim.Fill ()
  42. };
  43. TreeViewTextFilter<object> filter = new (_treeView);
  44. _treeView.Filter = filter;
  45. tfSearch.TextChanged += (s, e) =>
  46. {
  47. filter.Text = tfSearch.Text;
  48. if (_treeView.SelectedObject is { })
  49. {
  50. _treeView.EnsureVisible (_treeView.SelectedObject);
  51. }
  52. };
  53. _treeView.AddObjects (AppDomain.CurrentDomain.GetAssemblies ());
  54. _treeView.AspectGetter = GetRepresentation;
  55. _treeView.TreeBuilder = new DelegateTreeBuilder<object> (ChildGetter, CanExpand);
  56. _treeView.SelectionChanged += TreeView_SelectionChanged;
  57. // TextView for details
  58. _textView = new ()
  59. {
  60. X = Pos.Right (_treeView),
  61. Y = Pos.Top (_treeView),
  62. Width = Dim.Fill (),
  63. Height = Dim.Fill (),
  64. ReadOnly = true,
  65. };
  66. // Menu setup
  67. _showPrivateCheckBox = new ()
  68. {
  69. Title = "_Include Private"
  70. };
  71. _showPrivateCheckBox.CheckedStateChanged += (s, e) => ShowPrivate ();
  72. _highlightModelTextOnlyCheckBox = new ()
  73. {
  74. Title = "_Highlight Model Text Only"
  75. };
  76. _highlightModelTextOnlyCheckBox.CheckedStateChanged += (s, e) => OnCheckHighlightModelTextOnly ();
  77. menuBar.Add (
  78. new MenuBarItem (
  79. "_File",
  80. [
  81. new MenuItem
  82. {
  83. Title = "_Quit",
  84. Action = Quit
  85. }
  86. ]
  87. )
  88. );
  89. menuBar.Add (
  90. new MenuBarItem (
  91. "_View",
  92. [
  93. new MenuItem
  94. {
  95. CommandView = _showPrivateCheckBox
  96. },
  97. new MenuItem
  98. {
  99. Title = "_Expand All",
  100. Action = () => _treeView?.ExpandAll ()
  101. },
  102. new MenuItem
  103. {
  104. Title = "_Collapse All",
  105. Action = () => _treeView?.CollapseAll ()
  106. }
  107. ]
  108. )
  109. );
  110. menuBar.Add (
  111. new MenuBarItem (
  112. "_Style",
  113. [
  114. new MenuItem
  115. {
  116. CommandView = _highlightModelTextOnlyCheckBox
  117. }
  118. ]
  119. )
  120. );
  121. // Add views in order of visual appearance
  122. win.Add (menuBar, lblSearch, tfSearch, _treeView, _textView);
  123. Application.Run (win);
  124. win.Dispose ();
  125. Application.Shutdown ();
  126. }
  127. private bool CanExpand (object arg) => arg is Assembly or Type or ShowForType;
  128. private IEnumerable<object> ChildGetter (object arg)
  129. {
  130. try
  131. {
  132. return arg switch
  133. {
  134. Assembly assembly => assembly.GetTypes (),
  135. Type type => Enum.GetValues (typeof (Showable))
  136. .Cast<Showable> ()
  137. .Select (v => new ShowForType (v, type)),
  138. ShowForType show => show.ToShow switch
  139. {
  140. Showable.Properties => show.Type.GetProperties (GetFlags ()),
  141. Showable.Constructors => show.Type.GetConstructors (GetFlags ()),
  142. Showable.Events => show.Type.GetEvents (GetFlags ()),
  143. Showable.Fields => show.Type.GetFields (GetFlags ()),
  144. Showable.Methods => show.Type.GetMethods (GetFlags ()),
  145. _ => Enumerable.Empty<object> ()
  146. },
  147. _ => Enumerable.Empty<object> ()
  148. };
  149. }
  150. catch (Exception)
  151. {
  152. return Enumerable.Empty<object> ();
  153. }
  154. }
  155. private BindingFlags GetFlags () =>
  156. _showPrivateCheckBox?.CheckedState == CheckState.Checked
  157. ? BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic
  158. : BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
  159. private string GetRepresentation (object model)
  160. {
  161. try
  162. {
  163. return model switch
  164. {
  165. Assembly assembly => assembly.GetName ().Name ?? string.Empty,
  166. PropertyInfo propertyInfo => propertyInfo.Name,
  167. FieldInfo fieldInfo => fieldInfo.Name,
  168. EventInfo eventInfo => eventInfo.Name,
  169. _ => model.ToString () ?? string.Empty
  170. };
  171. }
  172. catch (Exception ex)
  173. {
  174. return ex.Message;
  175. }
  176. }
  177. private void OnCheckHighlightModelTextOnly ()
  178. {
  179. if (_treeView is null)
  180. {
  181. return;
  182. }
  183. _treeView.Style.HighlightModelTextOnly = _highlightModelTextOnlyCheckBox?.CheckedState == CheckState.Checked;
  184. _treeView.SetNeedsDraw ();
  185. }
  186. private void Quit () { Application.RequestStop (); }
  187. private void ShowPrivate ()
  188. {
  189. _treeView?.RebuildTree ();
  190. _treeView?.SetFocus ();
  191. }
  192. private void TreeView_SelectionChanged (object? sender, SelectionChangedEventArgs<object> e)
  193. {
  194. if (_treeView is null || _textView is null)
  195. {
  196. return;
  197. }
  198. object? val = e.NewValue;
  199. object [] all = _treeView.GetAllSelectedObjects ().ToArray ();
  200. if (val is null or ShowForType)
  201. {
  202. return;
  203. }
  204. try
  205. {
  206. if (all.Length > 1)
  207. {
  208. _textView.Text = $"{all.Length} Objects";
  209. }
  210. else
  211. {
  212. StringBuilder sb = new ();
  213. sb.AppendLine (e.NewValue?.GetType ().Name ?? string.Empty);
  214. switch (val)
  215. {
  216. case Assembly assembly:
  217. sb.AppendLine ($"Location:{assembly.Location}");
  218. sb.AppendLine ($"FullName:{assembly.FullName}");
  219. break;
  220. case PropertyInfo propertyInfo:
  221. sb.AppendLine ($"Name:{propertyInfo.Name}");
  222. sb.AppendLine ($"Type:{propertyInfo.PropertyType}");
  223. sb.AppendLine ($"CanWrite:{propertyInfo.CanWrite}");
  224. sb.AppendLine ($"CanRead:{propertyInfo.CanRead}");
  225. break;
  226. case FieldInfo fieldInfo:
  227. sb.AppendLine ($"Name:{fieldInfo.Name}");
  228. sb.AppendLine ($"Type:{fieldInfo.FieldType}");
  229. break;
  230. case EventInfo eventInfo:
  231. sb.AppendLine ($"Name:{eventInfo.Name}");
  232. sb.AppendLine ("Parameters:");
  233. if (eventInfo.EventHandlerType?.GetMethod ("Invoke") is { } invokeMethod)
  234. {
  235. foreach (ParameterInfo parameter in invokeMethod.GetParameters ())
  236. {
  237. sb.AppendLine ($" {parameter.ParameterType} {parameter.Name}");
  238. }
  239. }
  240. break;
  241. case MethodInfo methodInfo:
  242. sb.AppendLine ($"Name:{methodInfo.Name}");
  243. sb.AppendLine ($"IsPublic:{methodInfo.IsPublic}");
  244. sb.AppendLine ($"IsStatic:{methodInfo.IsStatic}");
  245. sb.AppendLine ($"Parameters:{(methodInfo.GetParameters ().Length > 0 ? string.Empty : "None")}");
  246. foreach (ParameterInfo parameter in methodInfo.GetParameters ())
  247. {
  248. sb.AppendLine ($" {parameter.ParameterType} {parameter.Name}");
  249. }
  250. break;
  251. case ConstructorInfo constructorInfo:
  252. sb.AppendLine ($"Name:{constructorInfo.Name}");
  253. sb.AppendLine ($"Parameters:{(constructorInfo.GetParameters ().Length > 0 ? string.Empty : "None")}");
  254. foreach (ParameterInfo parameter in constructorInfo.GetParameters ())
  255. {
  256. sb.AppendLine ($" {parameter.ParameterType} {parameter.Name}");
  257. }
  258. break;
  259. }
  260. _textView.Text = sb.ToString ().Replace ("\r\n", "\n");
  261. }
  262. }
  263. catch (Exception ex)
  264. {
  265. _textView.Text = ex.Message;
  266. }
  267. _textView.SetNeedsDraw ();
  268. }
  269. private enum Showable
  270. {
  271. Properties,
  272. Fields,
  273. Events,
  274. Constructors,
  275. Methods
  276. }
  277. private sealed class ShowForType
  278. {
  279. public ShowForType (Showable toShow, Type type)
  280. {
  281. ToShow = toShow;
  282. Type = type;
  283. }
  284. public Showable ToShow { get; }
  285. public Type Type { get; }
  286. public override bool Equals (object? obj) =>
  287. obj is ShowForType type && EqualityComparer<Type>.Default.Equals (Type, type.Type) && ToShow == type.ToShow;
  288. public override int GetHashCode () => HashCode.Combine (Type, ToShow);
  289. public override string ToString () => ToShow.ToString ();
  290. }
  291. }