Practical Example To Visualize Entities In Live Application Using MSAGL
Finding it difficult to understand the complex relationship between the different objects which are part of an application? Think of Visualizing the objects and their state when the application is running, Seems exciting right?
Yes, It's possible with the little help from MSAGL(Microsoft Automatic Graph Layout) and some boilerplate code to do that. I have created a sample application demonstrating how it can be done, including the state of these objects in a live manner.
I would recommend you to go through MSAGL Basics
Check out the video here:
using Microsoft.Msagl.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace MSAGL_Demo
{
public interface INodeRepository
{
void AddNode(Node node);
void OnActiveNodeChanged(string obj);
}
public class NodeRepository : INodeRepository
{
private IList<Node> nodes = new List<Node>();
private Graph g = null;
public NodeRepository() { g = new Graph(); }
public event Action Invalidate;
public void AddNode(Node node)
{
if (node == null) throw new ArgumentNullException("Node is null");
nodes.Add(node);
}
public Graph Visualize()
{
g.Directed = true;
foreach (var item in nodes)
{
g.AddNode(item.ToString());
}
foreach (var item in nodes)
{
var node = nodes.FirstOrDefault(n => n.GetType() == item.GetType().BaseType);
if (node != null)
{
g.AddEdge(item.ToString(),node.ToString());
}
}
return g;
}
public void OnActiveNodeChanged(string currentActiveNode)
{
if(string.IsNullOrEmpty(currentActiveNode)) throw new ArgumentNullException(nameof(currentActiveNode));
var activeNode = g.FindNode(currentActiveNode);
if (activeNode != null)
{
activeNode.Attr.FillColor = Color.Green;
Invalidate();
}
}
}
public class Node
{
public event Action<string> ActiveNodeChanged;
public Node(INodeRepository nodeRepository)
{
nodeRepository.AddNode(this);
ActiveNodeChanged += nodeRepository.OnActiveNodeChanged;
}
private bool isActive;
public bool IsActive
{
get
{
return isActive;
}
set
{
isActive = value;
if(isActive)
{
ActiveNodeChanged(this.ToString());
}
}
}
}
//Chain of Responsibility
//Node Hierarchy
public class ParentExecutor:Node
{
protected ParentExecutor executor;
protected INodeRepository m_nodeRepository;
public ParentExecutor(INodeRepository nodeRepository):base(nodeRepository) { m_nodeRepository = nodeRepository; }
public virtual void Execute()
{
IsActive = true;
Thread.Sleep(3000);
Console.WriteLine($"{nameof(ParentExecutor)} Executing");
}
}
public class ChildExecutorI : ParentExecutor
{
public ChildExecutorI(INodeRepository nodeRepository):base(nodeRepository)
{
executor = new ParentExecutor(nodeRepository);
}
public override void Execute()
{
IsActive = true;
Thread.Sleep(3000);
Console.WriteLine($"{nameof(ChildExecutorI)} Executing");
if (null != executor)
{
executor.Execute();
}
}
}
public class ChildExecutorII : ParentExecutor
{
public ChildExecutorII(INodeRepository nodeRepository) : base(nodeRepository)
{
executor = new ChildExecutorI(nodeRepository);
}
public override void Execute()
{
IsActive = true;
Thread.Sleep(3000);
Console.WriteLine($"{nameof(ChildExecutorII)} Executing");
if (null != executor)
{
executor.Execute();
}
}
}
public class ChildExecutorIII : ParentExecutor
{
public ChildExecutorIII(INodeRepository nodeRepository) : base(nodeRepository)
{
executor = new ChildExecutorII(nodeRepository);
}
public override void Execute()
{
IsActive = true;
Thread.Sleep(3000);
Console.WriteLine($"{nameof(ChildExecutorIII)} Executing");
if (null != executor)
{
executor.Execute();
}
}
}
}
Driver Code:
I hope this exercise serves as a starting point to visualize the different entities involved in a live application, helping developers to better understand the various entities involved in an application and the relationship between them.
Comments
Post a Comment