Once added, reference the CSS and JS files of bootstrap in MVC views.
Still if you do not wish to use BootStrap, you may have full control over styling of the TreeView control where you can manually style as you like.
Source data collection means the collection (List) of entities which should be displayed in the TreeView control. The entities in source data collection should actually represent child and parent relations.
public class ProductCategory
{
public int ProductCategoryId { get; set; }
public string ProductCategoryName { get; set; }
public string ProductCategoryDescription { get; set; }
}
public class ProductCategoryLevel
{
public int ProductCategoryLevelId { get; set; }
public int ProductCategoryId { get; set; }
public int ParentProductCategoryId { get; set; }
public ProductCategory ProductCategory { get; set; }
public ProductCategory ParentProductCategory { get; set; }
}
Here, ProductCategoryLevel defines parent-child relations between each ProductCategory instance. This can be any similar object in your application. Such as, Employee and Employee reporting levels, etc.
Step - 5 Configure mapping profile for data transformation
- In order to convert source data collection into TreeView compatible data, we need to define mapping between objects. The mapping should be configured during application start
Make sure to import following namespaces:
using DTech.Models;
using DTech.Core.Builders;
Following how we have configured mapping profile for our demo project -
using AutoMapper;
using DTech.Models;
using TreeViewHelper.Mvc.Demo.Models;
protected void Application_Start()
{
......
SetupMappingProfile();
}
public static void SetupMappingProfile()
{
AutoMapper.Mapper.CreateMap<ProductCategoryLevel, HierarchyNodeRawModel>()
.ForMember(dest => dest.NodeId, opt => opt.MapFrom(src => src.ProductCategoryLevelId))
.ForMember(dest => dest.EntityId, opt => opt.MapFrom(src => src.ProductCategoryId))
.ForMember(dest => dest.ParentEntityId, opt => opt.MapFrom(src => src.ParentProductCategoryId))
.ForMember(dest => dest.NodeTitle, opt => opt.MapFrom(src => src.ProductCategory.ProductCategoryName))
.ForMember(dest => dest.NodeDescription, opt => opt.MapFrom(src => src.ProductCategory.ProductCategoryDescription));
}
Namespace DTech.Models is supplied with the Nuget package, and contains models which are compatible with the TreeView control.
Type HierarchyNodeRawModel represents each node on TreeView.
NodeId >> Must be unique across the collection of HierarchyNodeRawModel. This can be same field as EntityId, if the relation is NOT many-to-many, and EntityId is unique across.
EntityId >> ID field representing child entity
ParentEntityId >> ID field representing parent entity
NodeTitle >> Ideally, a field to display the name of child entity on tree node
NodeDescription >> A field to display description about the child entity on tree node. This is optional, and can be set to blank, if your source collection doesn't have such field.
Step - 6 Build source data collection, and invoke View.
- Instantiate HierarchicalDataBuilder with the type of your source data collection
- Fetch source data collection from your data source (or service) in your controller
- Construct a string collection identifying ID (NodeId) to default selection of nodes in TreeView, if any.
- Transform the object into TreeView compatible type (i.e., HierarchicalDataModel)
- Pass the transformed model into the View hosting TreeView control
For simplicity of the demo, we have used following -
public ActionResult Index()
{
HierarchicalDataBuilder<ProductCategoryLevel> productCategoryLevelsBuilder = new HierarchicalDataBuilder<ProductCategoryLevel>();
List<ProductCategoryLevel> categoryLevels = ProductCategoryLevel.GetAll();
List<String> selectedCategoryLevels = new List<string>();
selectedCategoryLevels.Add("7");
selectedCategoryLevels.Add("4");
HierarchicalDataModel dataModel = productCategoryLevelsBuilder.CreateHierarchicalDataModel(categoryLevels, true, "/ProductCategory/Details/[id]", "[id]", selectedCategoryLevels, "HierarchyNodes");
return View(dataModel);
}
Remember, in more real scenario, the retrieval of source data collection, and constructing a String collection of selected NodeIds can be very much different from shown above. That can be from a real data store directly or via service depending upon architecture of your application.
Also, we are directly passing HierarchicalDataModel to the view, whereas in real-world scenario, this object may just be a part of a different model.
For example, There is a Product class which contains collection of ProductCategoryLevel. And the Product class should be used as a model for the view and NOT the transformed object of List<ProductCategoryLevel>. That means, Product class must have HierarchicalDataModel property in it, and should be assigned to the transformed object of List<ProductCategoryLevel>.
But for the demo purpose we are directly passing HierarchicalDataModel.
_Also, there are various overloads of CreateHierarchicalDataModel method in HierarchicalDataBuilder class, but for demo purpose we are using the one which provides maximum of functionality.
Each overload of this method is documented in the control, and will give you necessary details of the method and each of its parameters in the intellisense._
Some key notes about the method and its parameters, we have used in our demo -
HierarchicalDataModel dataModel = productCategoryLevelsBuilder.CreateHierarchicalDataModel(categoryLevels, true, "/ProductCategory/Details/[id]", "[id]", selectedCategoryLevels, "HierarchyNodes");
"/ProductCategory/Details/[id]" >> Parameter: ManageActionUrl - URL of the controller action which should be called when user clicks on "Manage" link. [id] is the ID placeholder, and will be replaced by the actual ID value of the node for which the button is displayed.
Please note, Manage link is not appearing always depending upon the overload which is used. And also, "Manage" can be renamed to "View", "Details", or anything you may want by supplying appropriate parameter in the method.
"[id]" >> Placeholder which should be similar to the ID placeholder specified in "ManageActionUrl"
"HierarchyNodes" >> Parameter: dataBindControlIDPrefix - In MVC when we bind a control array to a view, the Post action expects "name" property in a specific format to enable submitting of model. This should be as same as the ModelName.ControllArrayName.
For example, if your model bound to the view is Product, then this property should be supplied as "Product.HierarchyNodes", then only you will be able to get selected nodes in Post action.
Step - 7 Design your View
Make sure to import following namespaces
@using DTech.Models;
@using DTech.MVC;
Bind your view with the expected Model
@model DTech.Models.HierarchicalDataModel
_In more real scenario, this can be your Model containing source data collection and HierarchicalDataModel as its properties. For example, Product entity will have List<ProductCategoryLevel> as its property, and hence, HierarchicalDataModel should also be its property.
@Html.Raw(new _TreeViewHelper().GetTreeView(Model))
The above statement will render the data in a tree-view representation on the view.
In case, if the selection needs to be posted to a controller action, then it can be something like -
@using (Html.BeginForm())
{
@Html.Raw(new _TreeViewHelper().LoadTreeView(Model))
<input type="submit" value="Save and Continue" title="Save the selection, and continue to next screen to check the selected Items" />
}
Step - 8 Handle selection during Submit event
When user clicks a submit button on hosting view, an HttpPost controller action will be called with the submitted model. At this stage, the HierarchicalDataModel must be having selection and non-selection state for each tree node. Use GetSelectedNodeIDs method of the HierarchicalDataBuilder class to retrieve IDs of selected nodes.
For example,
[HttpPost]
public ActionResult Index(HierarchicalDataModel dataModel)
{
List<string> selectedProductCategoryLevelIDs = productCategoryLevelsBuilder.GetSelectedNodeIDs(dataModel.HierarchyNodes);
.......
}
Once the GetSelectedNodeIDs method is called, the String collection should contain IDs of selected nodes. This IDs will identify each selected node, and can be used further to save the selection in database or any other action as per your requirements.
Questions/ Discussions