How to deal with *many* context menus - c#

I'm re-writing in C# (with Winforms) an old VB6 app that uses a single context menu with multiple Items that change their Caption, Visible, and Enabled traits based on a monolithic function called "InitControls"
The function is 500 lines long and consists primarily of a switch statement that decides what controls to enable based on the selected item's tag (there's a tree view and list view; it selects the selected item from the active one and gets its tag). It then enables, disables, and modifies the text of the visible items, and clears any useless Separators. The original uses ActiveBar (a custom control) which allows it to change the text in one place and display the item in menus, context menus, and toolbars all at once.
I'm currently just re-implementing the logic line for line in C#, but I hate it because I'm not really fixing anything, just putting the problem into a new language (and possibly screwing it up in the process). I created a class that allowed me to change the text, enabled and visible properties of any "subscribed" Menu Items in one place and even add/remove event handlers for all subscriBed menu items. It works, and even seems apparently correct, but I'm pretty sure there's got to be a better way. My MainForm is ENORMOUS.
What is the standard .NET way of handling complex Context Menu and Toolbar logic?

From what I understand, you basically want to refactor a large switch-case method. Googling for "switch case refactoring" should give you several examples you can check out to find something that suits you best.
Usually, when you are refactoring a switch case, this means that you want to extract logic from each case block into a new class, possibly an implementation of an interface common to all cases. The right implentation of your class will depend on the condition of an individual case statement: this is called a Strategy pattern, because each condition demands a different strategy.
In your case, you need to slightly extend the pattern: you have a number of candidates for the context menu, each of them being able to handle a certain node type. In that case, your right-click handler needs to let them decide if they can provide functionality for a certain node.
[Edit]
To clarify a bit, I will provide a simple example.
I mentioned that individual implementations should be extracted into classes which implement the same interface, which should be responsible for changing menu items' appearance and state, based on the current condition.
interface IMenuStateManager
{
// this method updates state of one or
// more menu elements, according to the
// specified selected node info
void UpdateState(ISelectedNodeInfo info);
}
Our first, basic implementation of the IMenuStateManager interface will do nothing more that simply call other managers' implementations. This is called a Composite object pattern, because it allows us to treat a group of objects as a single object:
// composite class for a list of menu managers
class CompositeMenuStateManager : IMenuStateManager
{
private readonly IMenuStateManager[] _childManagers;
// params keyword will allow as to pass a comma separated list
// of managers, which is neat
public CompositeMenuStateManager(params IMenuStateManager[] managers)
{
_childManagers = managers;
}
// this is where the job gets done, but composite
// class doesn't do much work by itself
public void UpdateState(ISelectedNodeInfo info)
{
// allow each state manager to change its state
foreach (IMenuStateManager mgr in _childManagers)
{
mgr.UpdateState(info);
}
}
}
Now, you still have an enormous list of possible menu candidates, but now their logic is separated into different classes, and then wrapped in a single composite object.
IMenuStateManager _menuManager = new CompositeMenuStateManager
(
// note: each menu "manager" can manage one or more
// items, if you find it useful.
// For example, ClipboardMenuStateManager can be
// a composite manager itself (cut/copy/paste).
new ClipboardMenuStateManager(some params),
new SomeOtherMenuItemManager(various params),
new YetAnotherMenuItemManager(various params),
...
);
I guess that menu states get updated when a node is selected, but this is something you should easily adapt to your app. That particular event handler delegates the whole responsibility to our composite menu manager:
void Node_Selected(sender object, EventArgs args)
{
// find out which node was clicked
Node node = object as Node;
// get the data (model) node for this tree node
INodeData data = node.Tag as INodeData;
// create some info which will be passed to the manager.
// you can pass information that might be useful,
// or just simply pass the node data itself
ISelectedNodeInfo info = new SelectedNodeInfo(data, some other stuff);
// let the manager do the rest of the job
_menuManager.UpdateState(info);
}
Since you will probably have three menu items doing the same job at the same time (main menu, context menu, toolbar), you will probably want to make each IMenuStateManager implementation update all three of them at the same time. The simplest way should be to to pass an array of ToolStripItem objects, which is the base abstract class for several different menu elements:
class PrintMenuManager : IMenuStateManager
{
private readonly ToolStripItem[] _items;
// this constructor can accept several menu elements
public PrintMenuManager(params ToolStripItem[] items)
{
_items = items;
}
public void UpdateState(ISelectedNodeInfo node)
{
foreach (ToolStripItem item in _items)
{
// if node is printable, enable
// all "print" menu items and buttons
item.Enabled = (node.IsPrintable);
}
}
}
When creating the PrintMenuManager instance, you can pass all buttons and menu items which are related:
// (this should be one of the child managers in
// the composite menu manager, but you get it)
IMenuStateManager printMnuManaegr = new PrintMenuManager
(
this.printMenuItem,
this.printContextMenuItem,
this.printToolbarButton,
);
Whew, this turned out to be a lengthy one at the end. :)
Ok, that's about it for a start.

Related

Implementing navigation menu in Console app

I am trying to implement complex Console menu with several multilevel sub menus(path type menu). Maybe someone suggest what design pattern to use in my situation?
Example of top menu
* Main Menu *
1. List Virtual Servers
2. List Image Templates
3. Exit
If for example 1 is selected next sub menu appears
* List Virtual Servers *
1. Virtual server #1
2. Virtual server #2
3. Virtual server #3
4. Return
If for example 2 is selected next sub menu appears
* Command for Virtual server #2 *
1. Delete
2. Return
My current navigation code is below, this is only for the first top menu, not sure how to implement multilevel path type menu with full navigation up and down through menus.
static void Main(string[] args)
{
Console.WriteLine("1. List Virtual Servers" +
Environment.NewLine + "2. List Image Templates" +
Environment.NewLine + "3. Exit");
var input = Console.ReadKey();
var key = input.KeyChar;
int value;
if (int.TryParse(key.ToString(), out value))
{
Console.WriteLine();
RouteChoice(value);
}
else
{
Console.WriteLine("Invalid Entry.");
}
Console.Write("Press any key to exit...");
Console.ReadKey(false);
Console.ReadLine();
}
private static void RouteChoice(int menuChoice)
{
switch (menuChoice)
{
case 1:
GetVirtualServers();
break;
case 2:
GetImageTemplate();
break;
default:
Console.WriteLine("Invalid Entry!");
break;
}
}
My idea is to model a hierarchy of menu items as a tree and to traverse this tree when a user navigates through the menu. From design patterns perspective it would be a mix of Composite and Command + some tree traversing. In order to do so we need:
A base class BaseCommand to model each command in your menu.
A base class Command derived from BaseCommand for menu items that performs some logic - for leafs in the tree.
A base class CompositeCommand derived from BaseCommand for commands with children. This class will have Children property which will store objects of type BaseCommand.
Every command that can perform some logic e.g. Virtual server #1 should be derived from Command.
Every command that has children e.g. List Virtual Servers should be derived from CompositeCommand.
At the beginning of your program you should create a tree of commands. In your case in the root of this tree we will find Main Menu. The Children property of Main Menu will contain references to commands for List Virtual Servers, List Image Templates, Exit and so on.
The last part of this solution is a manager. The manager is a class that has to keep a track where we are in the tree. When the manager receives an input from a user, he can do 3 things: execute the current command if it is a leaf, move to the parent of the current command if a user selects Return, move to a child of the current command if it has one.
I've written a console menu which may be useful as a starting point to you.
CMenu is a lightweight, low-ceremony framework for building console menus in .Net. Instead of manually prompting the user for input and parsing it, you define commands in a short, structured and comprehensive way, and let CMenu handle the rest.
CMenu aims for low overhead - simple stuff should be simple to implement. If you don't use a feature, you don't need to know anything about it.
At the same time, complex scenarios are supported. Large menus can easily be split into several classes. Background self-configuration. You do not have to worry about all the annoying details involved in larger menus, it will just work.
Most importantly, it is very simple and fast to use. Commands can be abbreviated, a smart parser enables even partial matching. A help command is integrated.
It was not written with this numbered style of operation in mind, but it can be emulated and should work perfectly if you name the commands "1. foo", "2. bar" etc.
The inheritance system very simple (just derive from CMenuItem and override Execute), or if you want you can even just use lambdas instead.
var menu = new CMenu ();
menu.Add ("1. foo", s => Console.WriteLine ("Foo!"));
menu.Add ("2. bar", s => Console.WriteLine ("Bar!"));
menu.Run ();
Menu trees are supported very well, see this page for examples. As an example (there are other ways to create hierarchical menus):
var m = new CMenu () {
new CMenuItem ("1") {
new CMenuItem ("1", s => Console.WriteLine ("1-1")),
new CMenuItem ("2", s => Console.WriteLine ("1-2")),
},
new CMenuItem ("2") {
new CMenuItem ("1", s => Console.WriteLine ("2-1")),
new CMenuItem ("2", s => Console.WriteLine ("2-2")),
},
};
Update: Selection via single number key press will be included natively in the next release (0.8).

Managing prerequisites with MEF and Caliburn Micro

Lets say I have a component with a number of smaller components which check prerequisites before the first one will be initialized. They are not dependent on one another so I don't care about order and would like them to run simultaneously. I am using MEF and Caliburn.Micro for presentation.
I thought about this setup:
class Big
{
[ImportMany]
public IEnumerable<IBigPrerequisite> Prerequisites {get; set;}
public void Initialize(){...}
}
and
interface IBigPrerequisite
{
public bool IsBusy {...}
public bool Allow {...}
public void StartChecking();
}
Now what I would like to accomplish with this is that the classes implementing IBigPrerequisite can open up a window (for example "File X was not found - this could lead to errors. Continue?") - this should be possible.
But I would only want one window to be visible at a time. How would I accomplish that besides just going synchronously?
EDIT - since the question seemed too vague
I need these Actions to run specifically before Big will be activated. Let's say we switch up the activation logic to something like this:
Big big; //we got this through Importing somewhere in composition
var allow = true;
var count = 0;
if(!pre.Any()) //no prerequisites, show window immediately
windowManager.ShowWindow(big)
foreach(var pre in big.Prerequisities)
{
pre.PropertyChanged += (s, args) =>
{
if(args.PropertyName == "IsBusy" && !pre.IsBusy) // if a prerequisite finished it's check
{
allow = allow && pre.Allow; //if one prerequisite says nay we could just return, actually...
count++;
if(count == big.Prerequisites.Count() && allow)
windowManager.ShowWindow(big);
}
}
pre.StartChecking();
}
Now, I explicitly want the classes implementing IBigPrerequisite to be able to open a window, but in case all prerequisites are met (no user interaction required) no window should be showing. I do not wish to open up a window for every class here.
I am looking for a way to, say, give the IBigPrerequisite (which should probably be called IPrerequisiteViewModel anyways) a property like bool RequestsWindow {get;} and have the View only created when a) the viewmodel requests it and b) no other prerequisite window is open at the time.
Note: the code here is for illustration only as I am not sure how to implement this behaviour yet. I am not experienced with these frameworks (and concepts) so if this question seems silly please bear with me.
You are mixing concepts here.
Active view management in Caliburn.Micro is handled by the Conductor class. A Conductor-derived ViewModel can display a large number of Screen-derived ViewModels (or other Conductors). Available items are stored in the Items property.
You can find a much better description at "Screens, Conductors and Composition"
MEF has nothing to do with the Conductors and the composition mechanism, although it can be used to pass a list of items to a conductor. You can define an [ImportMany] constructor parameter or public property that receives the Screens to display during initializations and store them in the conductor's Items property.
Using a constructor parameter is more elegant, as you won't have to copy the items from your property's setter to the Items property.
Finally, you shouldn't display messages when creating your views and viewmodels. This is something that should be left for a later step, eg. during the Activate method. The Conductors and MEF get the parts together and build the UI. Executing actions and talking to the user should be done only after the composition step has finished.
I am going to answer this question myself detailing how I ended up solving this.
I made a LoaderViewModel : Conductor<PropertyChangedBase>.Collection.OneActive, IChild<Shell> and gave it a Queue<PropertyChangedBase>.
It has Show/HideWindow methods by traversing the Parent-Properties until it arrives at the Window-Level.
It has Queue and Dequeue methods. Queue is used when PropertyChanged is fired on a RequestsView-Property and calls Dequeue if there's either no ActiveItem or the ActiveItem is not marked as busy. Dequeue will activate a new item if there is one in the queue and then call ShowWindow, if there is no item it will call HideWindow instead.
The initial HideWindow is done in the ViewAttached-Event since if the window is hidden, CM seems to have some strange behaviour. Here, the parallel checking of the prerequisites is started and an event-handler registered similar to the one in the first post.
Sorry for being verbose, but the code has gotten a bit lengthy. If someone wants me to post it up write a comment.

WPF: property similar to WinForms Modified

In WinForms controls like a TextBox have property Modified that gets value "true" after changing the control's content and may be set to "false" manually. Their WPF analogues seem not to have such property (neither IsModified in new naming style). So do I have to handle their modifying events myself or there's some more convenient way?
For example I have few textboxes and a function, which combines their contents into one document for preview. Opening the preview I want to keep an old content for the document, if none of the textboxes was changed or to call the function to produce new document's content if at least one textbox was edited.
In WPF it's easier to control everything through ViewModel/Model... This might be too much/not what you're looking for. But through experience, I feel that the pattern below pays off in easy usage.
Wrap your simple data class (with all the properties that it is using now/in your question now) in a class/Model that implements IEditableObject, INotifyPropertyChanged and possibly IEquitable. Lets call your class Data.
In a wrapper class create fields:
Data _current;
Data _proposed;
Data _previous;
IEditableObject requires you to implement BeginEdit(), EndEdit() and CancelEdit().
in them you need to control the state _current, proposed, and previous. For example,
public void CancelEdit()
{
_current = _previous;
_proposed = null;
}
public void EndEdit()
{
_previous = _proposed;
}
public void BeginEdit()
{
_proposed = _current;
}
You might need more logic in methods above, so this is just an example. The key of knowing if your object has changes is implementing a flag, lot's of people call it IsDirty:
pubic bool IsDirty { get { return _current != _previous; } }
Now the user of this class can easily check the state. Oh, and on more thing each property would have the following mechanism:
public string Example
{
get { return _current.Example;}}
set
{
if(_current.Example == value) return;
BeginEdit();
_current.Example = value;
RaisePropertyChanged (() -> Example);
}
}
What's nice about implementing IEditableObject, all controls respond to it, DataGrid is a good example and also you can easily return to the original state by cancelling edit.
Anyway, there are lots of samples that you should browse for. I just hope to can get you started onto that path...
P.S. this pattern was used before WPF came out, its super common in WinForms as well
WPF doesn't have that because UI is not Data and therefore your UI is not the right place to store information about whether your data has changed or not.
Crappy dinosaur winforms doesn't allow a clean and true separation between UI and application logic/data and therefore has all sorts of horrible hacks in order to mash together these completely separate concepts.
You must learn to develop correctly, using the MVVM pattern. Then you will realize there's no sense in placing state data on any UI elements.

IHierarchyData and IHierarchicalEnumerable in Winforms

Currently,I know how to do a lazy implementation of the loading procedure of the nodes in a treeview control, and read the related questions in stackoverflow, but I'm also reading about IHierarchyData and IHierarchicalEnumerable interfaces in asp.net (I didn't know to code asp.net) that allow to bind a collection to a treeview in order to display the items automatically.
It would like to know if I can do the same in winforms and C#. I think that the interfaces previous mentioned are not available in winforms.
Thanks.
The Windows Forms TreeView does not know how to bind to an IHierarchyData instance, which isn't surprising given that the IHierarchyData and related interfaces are intended for consumption by web controls (especially site maps).
However, it's really not too hard to build your own data binding class. This seemed like an interesting problem so I threw one together just for fun. I'll walk you through the inner workings.
First, create a basic Component class. Visual Studio will start you off with code like this:
public partial class TreeViewHierarchyBinding : Component
{
public TreeViewHierarchyBinding()
{
InitializeComponent();
}
public TreeViewHierarchyBinding(IContainer container)
{
container.Add(this);
InitializeComponent();
}
}
One obvious piece of "state" this component needs to have is a mapping from each TreeNode to its IHierarchyData. Now we can hack around this by throwing it in the TreeNode's Tag property, but let's aim to make this component as non-invasive as possible and keep track of its own state. Hence, we'll use a dictionary. Add this field to the class:
private Dictionary<TreeNode, IHierarchyData> nodeDictionary = new
Dictionary<TreeNode, IHierarchyData>();
Now, at a minimum, this component needs to know how to populate a specific parent TreeNode of a TreeView class from its correspondingly bound IHierarchyData, so let's write that code next:
private void PopulateChildNodes(TreeNodeCollection parentCollection,
IHierarchicalEnumerable children)
{
parentCollection.Clear();
foreach (object child in children)
{
IHierarchyData childData = children.GetHierarchyData(child);
TreeNode childNode = new TreeNode(childData.ToString());
if (childData.HasChildren)
{
childNode.Nodes.Add("Dummy"); // Make expandable
}
nodeDictionary.Add(childNode, childData);
parentCollection.Add(childNode);
}
}
private void UpdateRootNodes(TreeView tv, IHierarchyData hierarchyData)
{
if (tv == null)
{
return;
}
tv.Nodes.Clear();
if (hierarchyData != null)
{
IHierarchicalEnumerable roots = hierarchyData.GetChildren();
PopulateChildNodes(tv.Nodes, roots);
}
}
This part should be pretty straightforward. The first method just populates a TreeNodeCollection (i.e. the Nodes property of a TreeNode) with the hierarchy obtained from an IHierarchyData instance, using the IHierarchyEnumerable interface. The only really interesting things this method does are:
Adding a dummy node when the IHierarchyData instance has children; this makes the "+" visible in the tree view, otherwise we wouldn't be able to expand any deeper; and
Adding the newly-added node to the dictionary with the IHierarchyData instance it matches with.
The second method is even simpler, it does the initial "binding work", replacing whatever is in the root of the tree with our top-level IHierarchyData instance.
The next thing our component needs to be able to do is hook the loading events from the TreeView to perform lazy-loading. Here's the code to do that:
private void RegisterEvents(TreeView tv)
{
tv.BeforeExpand += TreeViewBeforeExpand;
}
private void UnregisterEvents(TreeView tv)
{
tv.BeforeExpand -= TreeViewBeforeExpand;
}
private void TreeViewBeforeExpand(object sender, TreeViewCancelEventArgs e)
{
if (e.Node.Checked)
{
return;
}
IHierarchyData hierarchyData;
if (nodeDictionary.TryGetValue(e.Node, out hierarchyData))
{
PopulateChildNodes(e.Node.Nodes, hierarchyData.GetChildren());
e.Node.Checked = true;
}
}
First two methods should be self-explanatory, and the third method is the actual lazy-loading code. We're cheating a little here, using the TreeNode.Checked property to delineate whether or not the child nodes have already been loaded so we don't do any unnecessary reloads. I always do this when I implement lazy-loaded trees because, in my experience, I almost never use the TreeNode.Checked property. However, if you do need to use this property for something else, you can either use a different property (like Tag), create another dictionary to hold the expanded states, or modify the existing dictionary to hold a composite class (containing the IHierarchyData as well as an Expanded property). I'm keeping it simple for now.
The rest should already make sense to you if you've implemented lazy-loading in a tree before, so let's skip ahead. Really the only thing left to do at this point is implement some designer/user properties that will actually wire up the tree and data:
private IHierarchyData dataSource;
private TreeView treeView;
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IHierarchyData DataSource
{
get { return dataSource; }
set
{
if (value != dataSource)
{
dataSource = value;
nodeDictionary.Clear();
UpdateRootNodes(treeView, value);
}
}
}
[Category("Behavior")]
[DefaultValue(null)]
[Description("Specifies the TreeView that the hierarchy should be bound to.")]
public TreeView TreeView
{
get { return treeView; }
set
{
if (value != treeView)
{
if (treeView != null)
{
UnregisterEvents(treeView);
}
treeView = value;
nodeDictionary.Clear();
RegisterEvents(value);
UpdateRootNodes(treeView, dataSource);
}
}
}
Easy peasy. We've got a DataSource property that accepts the root IHierarchyData, and a TreeView property which you'll be able to access from the designer. Again, simple stuff here, when the DataSource property is updated, we just reset the lookup and repopulate the root. When the TreeView property is updated we have to do a little more work, registering the events, making sure to unregister events from the old tree view, and doing all the same stuff we do when the data source changes.
That's really all there is to it! Open up the Windows Forms designer, drop a TreeView, then drop a TreeViewHierarchyBinding and set its TreeView property to the tree view you just dropped. Finally, in your code somewhere (i.e. in the Form_Load event), give it a data source:
private void Form1_Load(object sender, EventArgs e)
{
DirectoryInfo dir = new DirectoryInfo("C:\\");
treeViewHierarchyBinding1.DataSource = new FileSystemHierarchyData(dir);
}
(Note - this uses the example FileSystemHierarchyData that's on the MSDN page for IHierarchyData. The example isn't very robust, it doesn't check for UnauthorizedAccessException or anything, but it's good enough to demonstrate this).
And that's it. Run your app and watch it bind. You can now reuse the TreeViewHierarchyBinding component anywhere - just drop it on a form, assign it a TreeView, and give it an IHierarchyData instance as a data source.
I've put the complete code on PasteBin if you want a copy-and-paste version.
Have fun!
The interfaces are available, but will require you to add a reference to System.Web.UI. (It might also require you to use the full .NET Framework redistributable rather than the Client Profile, although I'm not certain about that.)
The larger question is: Does the WinForms TreeView control automatically understand how to work with these interfaces? I believe the answer to that question is "No", but you would need to test/verify that.
There's an interesting article here that shows you how to build extension methods to achieve what I think you're looking for. There is no native availability within the System.Windows.Forms.TreeView to bind to a collection from what I can find.
You CAN include System.Web.UI in your project to make the IHierarchyData and IHierarchicalEnumerable interfaces available, but the TreeView will not be able to attach to them without the extension methods.
The sample source code from the web site will let you bind any IDictionary collection to the TreeView.

Dynamic options dialog (using reflection)

Does anyone know of a good component (C# WinForms) which would allow creating an options (settings) form, given a custom class with a bunch of properties? I am not looking for something shiny, but something merely better than a property grid. I can easily take care of the visual part, but I simply don't want to lose time doing reflection to add and bind controls if it already exists.
I am pretty sure I've seen a Visual Studio options-like form somewhere before, which was created dynamically (with some attributes attached to the properties of the class, to allow grouping and additional info).
[Edit] For example, I might have an options class:
public class Options : SerializableOptions<Options>
{
[Category("General")]
[Name("User name")]
[Description("Some text")]
public string Username { get; set; }
[Category("General")]
[Name("Log in automatically")]
public bool LogInAutomatically { get; set; }
[Category("Advanced")]
// ConnectionType is enum
public ConnectionType ConnectionType { get; set; }
// ...
}
After passing it to this form, it would create two panels ("General" and "Advanced"), with a CheckBox and a TextBox on the first panel, and one ComboBox (with all available enums) on the second panel.
If there isn't such a control, what do you guys use? Manually add, populate, format and bind controls for each option?
I'm not aware of any controls that allow you to do this, but it isn't difficult to do yourself. The easiest way is to create the dialog shell, a user control which acts as the base class for the options "panels", one (or more) attribute to control the name and grouping information, and an interface (which the user control implements).
Each of your custom options panels derives from the user control and overrides some sort of Initialize() and Save() method (provided by the user control). It also provides your attribute (or attributes) that determine the name/grouping information.
In the dialog shell, reflectively inspect all public types from your assembly (or all loaded assemblies) looking for types that implement your interface. As you find a type, get the attributes to determine where to place it in your grouping (easiest thing here is to use a tree view), call Activator.CreateInstance to create an instance of the user control and store it in the Tag property. When the user clicks on an entry in the grouping (a tree node), get the Tag and set the panel which contains the user control to the object in the Tag property. Finally, when the user clicks "OK" on the dialog, loop through the tree nodes, get the Tag property and call the Save method.
Update:
Another option would be to use a property grid control. It doesn't have a "pretty" UI look to it, but it is very functional, already supports grouping by a category attribute, and allows a great deal of flexibility. You could go with a single property grid that shows all of the options, or go with a "hybrid" approach with a tree view that groups by major functions (plugin, capability, etc.), probably based on the type. When the user clicks that node, give the property grid the object instance. The only drawback to this approach is that when changes are made to the property grid values they are "live" in that the underlying property is immediately changed, which means there is no concept of "Cancel" short of saving a copy of each value that could change and performing some type of "reset" yourself.
I don't know if such a control exists, but writing the required reflection code is really not that hard. E.g. something like this:
// the class for which to create an UI
public class MyClass
{
public string Text { get; set; }
public int ID { get; set; }
}
...
// basic reflection code to build the UI for an object
var obj = new MyClass() { Text="some text", ID=3};
foreach (var pi in obj.GetType().GetProperties())
{
var name = pi.Name;
var type = pi.PropertyType;
var value = pi.GetValue(obj, null);
//now setup the UI control for this property and display the value
}
I accidentally found something similar to this, I remebered that I had this problem a while ago and thought I should share it.
Here is a simple example: http://blog.denouter.net/2008/08/simple-reflection-form.html. It uses reflection to create several controls based on object's properties.

Categories