C# Visual Object Explorer Dialog

Please note: This page has now been moved. Click here to go to the new site.

Often, when building visual applications I find that as I build the applications in stages, there are often times when I’d like to be able to quickly view what data is in the application memory without having to build the UI and link the data to a series of controls.

To solve this problem, I created a simple object explorer dialog that will accept an object as a parameter, and from that display the object and all properties and sub objects as a tree view.

This is surprisingly easy to do, and can be broken down into 3 steps.

We start with a simple Windows form with just a tree view control and a close dialog button:

1

We can then go to the code behind and we need a couple of methods to build the tree.  The first is the recursive method that calls itself repeatedly until the tree has been built:

private void CreateChildNode(TreeNode parent, object o)
        {
            Type t = o.GetType();
 
            IList<PropertyInfo> props = new List<PropertyInfo>(t.GetProperties());
 
            foreach (PropertyInfo prop in props)
            {
                object propValue = prop.GetValue(o, null);
                TreeNode tnProp = new TreeNode(prop.Name + " : " + prop.PropertyType.ToString());
                string value = propValue == null ? "Null value" : propValue.ToString();
 
                if (value == string.Empty)
                {
                    value = "No Value Specified";
                }
 
                TreeNode tnValue = new TreeNode(value);
                parent.Nodes.Add(tnProp);
 
                if (propValue is ICollection)
                {
                    IEnumerable items = propValue as IEnumerable;
                    int nodeNo = 0;
                    foreach (object i in items)
                    {
                        nodeNo++;
                        TreeNode tnNo = new TreeNode(nodeNo.ToString());
                        tnProp.Nodes.Add(tnNo);
                        this.CreateChildNode(tnNo, i);
                    }
                    if (nodeNo == 0)
                    {
                        // Empty collection
                        tnProp.Nodes.Add("Empty");
                    }
                }
                else if (propValue != null && propValue.GetType().Module.ScopeName != "CommonLanguageRuntimeLibrary")
                {
                    if (propValue.GetType().GetProperties().Length > 1)
                    {
                        this.CreateChildNode(tnProp, propValue);
                    }
                    else
                    {
                        tnProp.Nodes.Add(tnValue);
                    }
                }
                else
                {
                    tnProp.Nodes.Add(tnValue);
                }
            }
        }

As you can see, in the above code we get the object type, the object type name, handle any null values, and then we  create a node and do one of 3 things:

  • If the object implements ICollection, we iterate through all the items or we note the node as ‘Empty’.
  • If the object is a custom object then we either display its value, or if it has multiple properties we iterate through those.
  • If the object is a system type (string, int, etc.) we display the value.

We also need to create a separate starter method to create the initial parent node and for handling the possibility the initial object we’re given is a collection.  If this is the case we’ll actually be creating and displaying multiple trees.  The code for this is very similar to the above:

private void CreateTree(object o)
       {
           Type t = o.GetType();
           this.Text = t.ToString();
           TreeNode topNode = new TreeNode(t.Name.ToString() + " : " + t.ToString());
 
           if (o is ICollection)
           {
               foreach (object i in o as IEnumerable)
               {
                   topNode = new TreeNode(t.Name.ToString() + " : " + t.ToString());
                   this.CreateChildNode(topNode, i);
                   this.tvExplorer.Nodes.Add(topNode);
               }
           }
           else
           {
               topNode = new TreeNode(t.Name.ToString() + " : " + t.ToString());
               this.CreateChildNode(topNode, o);
               this.tvExplorer.Nodes.Add(topNode);
           }
       }

The final step is to set the initialiser to start the process off:

public ObjectExplorer(object obj)
        {
            InitializeComponent();
            this.CreateTree(obj);
        }

To use the object explorer we can then pass it any object and it will iterate through and display the contents:

Person p = new Person();
Person mum = new Person { Name = "Jill", DOB = DateTime.Now.AddYears(-56), Male = false, Gender = "Female" };
Person dad = new Person { Name = "Jack", DOB = DateTime.Now.AddYears(-59), Male = true, Gender = "Male" };
Person brother = new Person { Name = "James", DOB = DateTime.Now.AddYears(-22), Male = true, Gender = "Male" };
Person sister = new Person { Name = "Jen", DOB = DateTime.Now.AddYears(-18), Male = false, Gender = "Female" };
p.Siblings = new List<Person> { brother, sister };
p.Parents = new Person[] { mum, dad };
ObjectExplorer exp = new ObjectExplorer(p);
exp.ShowDialog();

Will give us:

2

And if we pass a collection as an object:

<pre>Person mum = new Person { Name = "Jill", DOB = DateTime.Now.AddYears(-56), Male = false, Gender = "Female" };
Person dad = new Person { Name = "Jack", DOB = DateTime.Now.AddYears(-59), Male = true, Gender = "Male" };
var Parents = new Person[] { mum, dad };
ObjectExplorer exp = new ObjectExplorer(Parents);
exp.ShowDialog();

3

A Very Simple MVVM Demonstration

Please note: This page has now been moved. Click here to go to the new site.

RandomNumberGeneratorWhen starting out with MVVM, it can take some time and research to really start to understand the concepts, and there is a wealth of information and opinion on the subject, to the point where it could become overwhelming..

Here I have decided to create a random number generator to demonstrate MVVM and data binding in a very simplistic way.

Firstly to the XAML. Here I have simply created a form with a textblock and a button. The button binds to a command to generate a random number, and the textblock then binds to the number to display.

<DockPanel LastChildFill="True">
      <Button Content="Generate" Command="{Binding Generate}" DockPanel.Dock="Bottom" Width="100" Margin="20"/>
      <TextBlock Text="{Binding Number}" Margin="10" HorizontalAlignment="Center"
                 FontSize="150" />
</DockPanel>

Before we can create our view model, we also need to create a command to bind our button to, as by default this isn’t directly provided for in WPF. To do this we can create a class that implements the ICommand interface, and accepts an Action() in the constructor. Set the CanExecute() to return true for this scenario as we don’t need to worry about disabling the button.

 public class ButtonCommand : ICommand
    {
        private Action action;

        public ButtonCommand(Action action)
        {
            this.action = action;
        }

        public void Execute(object parameter)
        {
            action();
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;
        
    }

Now that we have our command, we can create our view model class. This basically exposes 2 items, the string value of the number we want to display, and an implementation of the command we have just created.


public class MainWindowViewModel : INotifyPropertyChanged
    {
        private string number;

        private ICommand generate;

        public MainWindowViewModel()
        {

        }

        public string Number
        {
            get
            {
                if (this.number == null)
                {
                    return string.Empty;
                }
                return this.number;
            }

            private set
            {
                this.number = value;
                this.NotifyPropertyChanged("Number");
            }
        }

        public ICommand Generate
        {
            get
            {
                if (this.generate == null)
                {
                    this.generate = new ButtonCommand(() => this.GenerateNumber());
                }
                return this.generate;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string property)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }

        private void GenerateNumber()
        {
            Random rnd = new Random();
            this.Number = rnd.Next(1, 100).ToString();
        }
    }

There are a couple of things to notice here. Firstly, our view model implements the INotifyPropertyChanged interface. [Note: If we were making multiple view models, we’d want to abstract this out] This interface allows us to notify out view when a value changes. Here you can see that when we click our generate button, we fire the GenerateNumber() method which then updates our Number property. Not this is our ‘Number’ property, not the ‘number’ field. This way, via the ‘set’ accessor, we can then call the NotifyPropertyChanged() method, passing it the value “Number”. By doing this, any control on the view that is binding to ‘Number’ will be asked to update.

The last thing we need to do is set the data context of the view, so the view has something to bind to. We can do this in the views code behind constructor.


public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new MainWindowViewModel();
        }

I hope this shows how easy it is start out with MVVM, and decouple the the view from the view model. Through the use of views and view models, and taking advantage of data binding, we can build responsive user interfaces quickly and with minimal code. By decoupling the view from the view model, it should also be very easy to create unit tests for the view model, meaning we should be able to write better, bug-free code. In my next post, I shall demonstrate unit testing of the above application.

WPF and MVVM

Please note: This page has now been moved. Click here to go to the new site.

One of the most interesting features of the .NET framework I have been using in recent times is Windows Presentation Foundation which allows graphical interfaces to be described using XAML.  This allows rich user interfaces to be put together simply and easily.  One of main areas of thinking on top of WPF is the Model-View-ViewModel approach to application design, which allows for the ‘separation of concerns’ or layering of an application design, with each of those 3 areas only dealing with a particular area.

By separating the 3 layers out, we can make testing our application through the use of unit testing frameworks such as NUnit much simpler, and this in turn should lead to more stable, better designed applications.

The 3 layers are the ‘view’ which is effectively just the UI description in XAML.  There is some debate about how much code we can put in the view, but effectively it is just UI code and nothing else.  There should theoretically be no data stored in the UI.

The ‘view-model’ is a class object that is purely in C# [or VB.net] code and exposes the data and commands to the view.  The view model is not coupled to the view, the it has no knowledge of the view.  Because of this, all features of the view model should be testable.  We assign the view model to the view at run time through the use of a ‘data context’.

Models are all our other objects that do not directly provide data or services to the view.

Throughout the next few posts I aim to very simply demonstrate the basics of WPF and MVVM, and then move to some more complex scenarios.  I don;t plan on doing this through making a full application, but rather focus on small areas of detail that you may be able to incorporate into your own projects should you wish.

There are also many other advantages of WPF, that are enable through the use of frameworks such as Prism, which I will discuss when the time comes.

Finally, I would also like to say that I don;t believe WPF is the answer to everything.  For small, personal applications or throw-away applications that require a user interface, the investment in time and learning required for WPF may not be suitable.