Download Free Demos

Task Manager in MVC5

Here is a step-by-step tutorial on how to create a task manager project in MVC5. You can download a ready sample in MVC5.

task manager in mvc5

Project Description

1 . Task manager app contains a number of tasks and employees. Employees can handle the assigned tasks.

2 . One task is assigned to one employee. It can also be reassigned to another employee by the manager.

3 . An employee can change the status of a task assigned to him/her and view task details.

4 . The app includes two types of users: the Manager and the Employee.

5 . The Manager can add, edit and close all tasks.

6 . Task status is defined by task color.

7 . All user types have different access rights. To login, a user must enter the user ID and the password.

Proceed with the tutorial by completing the steps below or download task manager sample in MVC5.

Step 1. New ASP.NET MVC Project with MVC5 Template

At the very beginning we will create a new Microsoft Visual Studio 2013 project and install DHTMLX Scheduler .NET via Nuget.

Your actions:

1 . Open Visual Studio 2013

2 . Go to FileNewProject and select ASP.NET MVC Web Application in the desired programming language. Name it TaskManager.MVC5

3 . Select Next and then select an empty MVC template in the opened window

Step 2. Adding Model with User Credentials

In order to keep implementation of the login system separately from the rest of the application, we'll define it in a separate class-library project within the same solution.

We will build our membership system using ASP.NET Identity.

The following illustration shows the folder structure of the project:

 task manager project structure

Step 2.1. Creating a Project

Your actions:

1 . Select SolutionAddNew Project → Your language → WindowsClass Library

2 . In the Name box enter Scheduler.MVC5.Users

3 . In the Location box enter a name for the project folder

4 . Select Create directory for solution

5 . Click Ok

Step 2.2. Adding Core Libraries

Add references to the library via Nuget (Package Manager Console).

Note: Please, check your Default Project in all installations of the Nuget packages:

 core libraries

PM>Install-Package EntityFramework
PM>Install-Package Microsoft.AspNet.Identity.Core
PM>Install-Package Microsoft.AspNet.Identity.EntityFramework
PM>Install-Package Microsoft.AspNet.Identity.Owin
PM>Install-Package Microsoft.Owin.Host.SystemWeb -Version 2.1.0

Add the following references: System.Web

Step 2.3. Updating App.Config

Add connectionStrings to the app.config file:

<configuration>
<connectionStrings>
    <add name="TaskManagerString" connectionString="data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|\TaskManager.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

Step 2.4. Implementing Basic Classes

  • ApplicationUser

ApplicationUser class represents a user entry of the application. It should be inherited from the IdentityUser class, that is the default user implementation of EntityFramework.

UserIdentityDbContext represents a class that uses the default entity types for .NET Identity Users, Roles, Claims, Logins.

1 . Create a folder UserStore in the project

2 . Select UserStore, right click AddNew Item → Your language → CodeClass

3 . Enter ApplicationUser in the Name box

4 . Click Ok

Update the code as follows:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
 
namespace Scheduler.MVC5.Users
{
    /// <summary>
    ///  represents default EntityFramework IUser implementation
    /// </summary>
    public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(AppUserManager manager)
        {
            return await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        }
    }
    /// <summary>
    /// represents a class that uses the default entity types for ASP.NET Identity Users, Roles, Claims, Logins
    /// </summary>
    public class UserIdentityDbContext : IdentityDbContext<ApplicationUser>
    {
        public UserIdentityDbContext()
            : base("TaskManagerString")
        {
        }
 
        public UserIdentityDbContext Create()
        {
            return new UserIdentityDbContext();
        }
 
        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<ApplicationUser>().ToTable("Users");
            modelBuilder.Entity<IdentityRole>().ToTable("Roles");
            modelBuilder.Entity<IdentityUserRole>().ToTable("UserInRoles");
 
        }
    }
}

Note: TaskManagerString is the name of the connection string for the task manager database. It is contained in the app.config

  • AppUserManager

Exposes user related APIs, which will automatically save changes to the UserStore.

1 . Add a New Item to the project with the Name UserManager

2 . Update the code as follows:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
 
namespace Scheduler.MVC5.Users
{
    /// <summary>
    /// Exposes user related APIs which will automatically save changes to the UserStore
    /// </summary>
    public class AppUserManager : UserManager<ApplicationUser>
    {
        public AppUserManager(IUserStore<ApplicationUser> store) : base(store)
        {
        }
        public AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
        {
            var manager =
                new AppUserManager(new UserStore<ApplicationUser>(context.Get<UserIdentityDbContext>()));
 
            return manager;
        }
    }
}
  • UserIdentityDbContext

UserIdentityDbContext class will delete, recreate, and optionally reseed the database only if the model has changed since the database was created.

1 . Select UserSrore and right click Add &rarr→ New Item&rarr→ Your language &rarr→ CodeClass

2 . Enter UserIdentityDbContext in the Name box

3 . Click Ok

4 . Update the code as follows:

using System.Data.Entity;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
 
namespace Scheduler.MVC5.Users
{
    public class UserIdentityDbContextInit : CreateDatabaseIfNotExists<UserIdentityDbContext>
    {}
}

5 . If you need some default data in the database, you need to override the Seed() method.

The default implementation does nothing. We'll update it in order to create the default users and roles:

using System.Data.Entity;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
 
namespace Scheduler.MVC5.Users
{
    public class UserIdentityDbContextInit : CreateDatabaseIfNotExists<UserIdentityDbContext>
    {
        protected override void Seed(UserIdentityDbContext context)
        {
            InitTables(context);
            base.Seed(context);
        }
 
        private void InitTables(UserIdentityDbContext context)
        {
            var userManager = new AppUserManager(new UserStore<ApplicationUser>(context));
            var rolemanager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
            var names = new[]{"Manager","David","Dana","Linda","John"};
            var roles = new[]{"Manager", "Employee"};
 
            //Create role(s) if not exists
 
            foreach (var role in roles)
            {
                if (!rolemanager.RoleExists(role))
                {
                    rolemanager.Create(new IdentityRole(role));
                }
            }
 
            //Create user(s)
 
            foreach (var name in names)
            {
                var user = new ApplicationUser()
                {
                    UserName = name
                };
                var result = userManager.Create(user, "password");
 
                //and adding user role(s)
 
                if (result.Succeeded)
                {
                    string role = name == "Manager" ? "Manager" : "Employee";
                    userManager.AddToRole(user.Id, role);
                }
            }
        }
    }
}
  • SignInHelper

This class will handle login/logout user attempts.

1 . Add a New Item to the project with the Name SignInHelper

2 . Update the code as follows:

using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
 
namespace Scheduler.MVC5.Users
{
   public class SignInHelper
    {
        public AppUserManager AppUserManager { get; private set; }
        public IAuthenticationManager AuthenticationManager { get; set; }
 
        public SignInHelper(AppUserManager userManager, IAuthenticationManager authManager)
        {
            this.AppUserManager = userManager;
            this.AuthenticationManager = authManager;
        }
 
 
        public async Task SignInAsync(ApplicationUser user, bool isPersistent, bool rememderBrowser)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie,
                DefaultAuthenticationTypes.TwoFactorCookie);
            var userIdentity = await user.GenerateUserIdentityAsync(AppUserManager);
            if (rememderBrowser)
            {
                var rememberBrowserIdentity = AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(user.Id);
                AuthenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, userIdentity,
                    rememberBrowserIdentity);
            }
            else
            {
                AuthenticationManager.SignIn(new AuthenticationProperties(){IsPersistent = isPersistent},userIdentity);
            }
        }
 
        public async Task<string> PasswordSignIn(string userName, string password, bool isPersistent)
        {
           var user = await AppUserManager.FindByNameAsync(userName);
            if (user == null)
            {
                return SignInStatus.Failure.ToString();
            }
            if (await AppUserManager.CheckPasswordAsync(user, password))
            {
                await SignInAsync(user, isPersistent, false);
                return SignInStatus.Success.ToString();
            }
            if (await AppUserManager.IsLockedOutAsync(user.Id))
            {
                return SignInStatus.LockedOut.ToString();
            }
            return SignInStatus.Failure.ToString();
        }
 
    }
}
  • AppUserManagerProvider

1 . Add into the project a new class named AppUserManagerProvider to the Scheduler.MVC5.Users

2 . Update the code as follows:

using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
 
namespace Scheduler.MVC5.Users
{
    public class AppUserManagerProvider
    {
       UserIdentityDbContext _dbUsers = new UserIdentityDbContext();
 
        UserIdentityDbContext Db
        {
            get
            {
                if (_dbUsers == null)
                    _dbUsers=new UserIdentityDbContext();
                return _dbUsers;
            }
        }
 
        private static AppUserManager _userManager;
        public static AppUserManager GetAppUserManager
        {
            get
            {
                return _userManager ??
                       (_userManager = HttpContext.Current.GetOwinContext().GetUserManager<AppUserManager>());
            }
            set
            {
                if (value != null)
                {
                    _userManager = value;
                }
            }
        }
 
        public List<ApplicationUser> Users
        {
            get { return Db.Users.ToList(); }
        }
 
        public string UserId { get { return HttpContext.Current.User.Identity.GetUserId(); } }
 
        public List<string> GetUserRolesName(string id)
        {
            return Db.Roles.Select(o=>o.Name).ToList();
        }
 
        public static IAuthenticationManager AuthenticationManager
        {
            get
            {
                return HttpContext.Current.GetOwinContext().Authentication;
            }
        }
    }
}

After that Build Library and Add Reference to the TaskManager.MVC5 site.

Step 3. Adding Model For Task Manager Data

The next step is to define the data model of our application and connect it to the database.

As at the previous step, we'll use the Code First approach.

The following illustration shows the folder structure of the project:

 add model for task manager data

Step 3.1. Creating a Project

Your actions:

1 . Select SolutionAddNew Project → Your language → WindowsClass Library.

2 . In the Name box enter TaskManager.MVC5.Model.

3 . In the Location box, enter a name for the project folder.

4 . Select Create directory for solution.

5 . Click Ok

Step 3.2. Adding Core Libraries

Add a package via Nuget(Package Manager Console):

Note: Please, check your Default Project in all installations of nuget packages:

 add core libraries

PM> Install-Package EntityFramework

 install entity framework

Step 3.3. Updating App.Config

Add connectionStrings to the app.config file:

<configuration>
<connectionStrings>
    <add name="TaskManagerString" connectionString="data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|\TaskManager.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

Step 3.4. Defining Model and Context

1 . Add a New Folder with name Modelto the project

2 . AddNew Items into the created folder (Status.cs, Task.cs, TaskManagerDbContext.cs)

Write two simple classes named Status and Task entity as shown below:

  • Status.cs
namespace TaskManager.MVC5.Model
{
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
 
    [Table("Statuses")]
    public class Status    {
        public int id { get; set; }
        [StringLength(50)]
        public string title { get; set; }
 
        [StringLength(10)]
        public string color { get; set; }
    }
}
  • Task.cs
namespace TaskManager.MVC5.Model
{
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
 
    public class Task
    {
        public int id { get; set; }
 
        [StringLength(256)]
        public string text { get; set; }
 
        public DateTime? start_date { get; set; }
 
        public DateTime? end_date { get; set; }
 
        [Column(TypeName = "text")]
        public string details { get; set; }
 
        public Guid? owner_id { get; set; }
 
        public Guid? creator_id { get; set; }
 
        public int? status_id { get; set; }
    }
}
  • TaskManagerDbContext.cs

We'll also override the Seed() method in order to show some initial statuses:

namespace TaskManager.MVC5.Model
{
    using System.Data.Entity;
 
    public class TaskManagerDbContext : DbContext
    {
        public TaskManagerDbContext()
            : base("name=TaskManagerString")
        {
        }
 
        public virtual DbSet<Status> Statuses { get; set; }
        public virtual DbSet<Task> Tasks { get; set; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Task>()
                .ToTable("Task");
 
            modelBuilder.Entity<Status>()
                .ToTable("Status");
        }
    }
 
    public class TaskManagerDbContextInit : CreateDatabaseIfNotExists<TaskManagerDbContext>
    {
        protected override void Seed(TaskManagerDbContext context)
        {
            InitTables(context);
            base.Seed(context);
        }
 
        private void InitTables(TaskManagerDbContext context)
        {
            /*
            if you need to create data tables
             */
            context.Statuses.AddRange(new[]
            {
               new Status(){title = "Waiting",color = "#5B9BE0"},
                new Status(){title = "In progress",color = "#FE7510"},
                new Status(){title = "Done",color = "#76B007"}
            });
        }
    }
}

Step 3.5. Creating Repository

A repository pattern is an abstraction layer between the logic of your application and the implementation of database access. Your access layer can be any from ADO.NET stored procedures to EF. It also excludes duplicated code and simplifies testing.

1 . Add a New Item Interface named IRepository to the current project

2 . Update the code as follows:

using System;
using System.Linq;
 
namespace TaskManager.MVC5.Model
{
    public interface IRepository : IDisposable
    {
        void Insert<T>(T entity) where T : class;
        IQueryable<T> GetAll<T>() where T : class;
        void Delete<T>(T entity) where T : class;
        void Update<T>(T entity) where T : class;
    }
}

3 . Add New Item Class named Repository

4 . Update the code as follows:

using System.Data.Entity;
 using System.Linq;
  
 namespace TaskManager.MVC5.Model
 {
     public class Repository : IRepository
     {
         private readonly TaskManagerDbContext context = new TaskManagerDbContext();
  
         public void Dispose()
         {
             context.Dispose();
         }
             public void Insert<T>(T entity) where T : class
         {
             if (entity == null) return;
             context.Entry(entity).State = EntityState.Added;
             context.SaveChanges();
         }
         public IQueryable<T> GetAll<T>() where T : class
         {
             return context.Set<T>();
         }
         public void Delete<T>(T entity) where T : class
         {
             if (entity == null) return;
             context.Entry(entity).State = EntityState.Deleted;
             context.SaveChanges();
         }
         public void Update<T>(T entity) where T : class
         {
             if (entity == null) return;
             context.Set<T>().Attach(entity);
             context.Entry(entity).State=EntityState.Modified;
             context.SaveChanges();
         }
     }
 }

Finally, Build Library and Add Reference to the TaskManager.MVC5 site.

Step 4. Adding the Required Files

Step 4.1. Setting Up Libraries

Install the following libraries to the created project via Nuget (Package Manager Console)

Note: Please, check your Default Project in all installations of NuGet packages:

package manager console

PM>Install-Package Microsoft.AspNet.Mvc
PM>Install-Package jQuery
Install-Package DHTMLX.Scheduler.NET
PM>Install-Package EntityFramework
PM>Install-Package Microsoft.AspNet.Identity.EntityFramework
PM>Install-Package Microsoft.AspNet.Identity.Owin

Add the following references: System.Runtime.Serialization

The following illustration shows the final folder structure of the project:

task manager mvc5

Step 4.2. Adding App.Config

Add connection string:

<configuration>
 <connectionStrings>
    <add name="TaskManagerString" connectionString="data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|\TaskManager.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

Configure the globalization settings of the application:

<system.web>
      <globalization culture="en-US"/>
</system.web>

Step 4.3. Updating Global.asax

To create a database, paste the following code to Global.asax

using System.Data.Entity;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Scheduler.MVC5.Users;
using TaskManager.MVC5.Model;
 
namespace TaskManager.MVC5
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
 
            //to create users table with/without data if not exists
            Database.SetInitializer(new TaskManagerDbContextInit());
            var db = new TaskManagerDbContext();
            db.Database.Initialize(true);
            //to create others tables with/without data if not exists
            Database.SetInitializer(new UserIdentityDbContextInit());
            var users = new UserIdentityDbContext();
            users.Database.Initialize(true);
        }
    }
}

Step 4.4. Adding Startup Class

1 . Add the OWIN Startup Class to your task manager project:

add new item

2 . Paste the following code to the created file:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using Owin;
using Scheduler.MVC5.Users;
 
[assembly: OwinStartup(typeof(TaskManager.MVC5.Startup))]
 
namespace TaskManager.MVC5
{
    public class Startup
    {
        public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
 
        public void Configuration(IAppBuilder app)
        {
            // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
            app.CreatePerOwinContext((new UserIdentityDbContext()).Create);
            app.CreatePerOwinContext<AppUserManager>((new AppUserManager(new UserStore<ApplicationUser>(new UserIdentityDbContext()))).Create);
 
 
            OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
 
            //This will used the HTTP header: "Authorization" Value: "Bearer 1234123412341234asdfasdfasdfasdf"
            app.UseOAuthBearerAuthentication(OAuthBearerOptions);
            // Enable the application to use a cookie to store information for the signed in user
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/LogOn")
            });
        }
    }
}

Step 4.5. Adding Models

Add a New Folder to the project with the name Models. We will add the following models into it:

  • AccountModels

1 . AddClass named AccountModels to the Models folder

2 . Update the code as follows:

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Security;
 
namespace TaskManager.MVC5.Models
{
 
    #region Model
     public class ChangePasswordModel
    {
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("Current password")]
        public string OldPassword { get; set; }
 
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("New password")]
        public string NewPassword { get; set; }
 
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("Confirm new password")]
        public string ConfirmPassword { get; set; }
    }
 
    public class LogOnModel
    {
        [Required]
        [DisplayName("User name")]
        public string UserName { get; set; }
 
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("Password")]
        public string Password { get; set; }
 
        [DisplayName("Remember me?")]
        public bool RememberMe { get; set; }
    }
 
     public class RegisterModel
    {
        [Required]
        [DisplayName("User name")]
        public string UserName { get; set; }
 
        [Required]
        [DataType(DataType.EmailAddress)]
        [DisplayName("Email address")]
        public string Email { get; set; }
 
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("Password")]
        public string Password { get; set; }
 
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("Confirm password")]
        public string ConfirmPassword { get; set; }
    }
    #endregion
}
  • TaskDetails

1 . AddClass named TaskDetails.cs to the Models folder

2 . Paste the following code:

using System.Collections.Generic;
using TaskManager.MVC5.Model;
 
namespace TaskManager.MVC5.Models
{
    public class TaskDetails
    {
        public Task Task { get; set; }
        public IEnumerable<Status> Statuses { get; set; }
        public TaskDetails(Task ts, IEnumerable<Status> st)
        {
            Task = ts;
            Statuses = st;
        }
    }
}

Step 4.6. Creating Views

In the Views folder of the project create the following folders: Shared, Account and System.

1 . Shared

The Shared folder is used to store views shared between controllers (layout page). Also this folder contains a user control partial view.

  • _Layout

At first you need to create a layout:

1 . Create a file called _Layout.cshtml inside of the shared folder 2 . Insert the following code into the created file:

<!DOCTYPE html>
 
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Task Manager</title>
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
    <link href="~/scripts/dhtmlxscheduler/dhtmlxscheduler_flat.css" rel="stylesheet" />
 
</head>
 
    <body>
 
        <div id="header">
 
            <div id="logindisplay">
                @Html.Partial("UserControl")
            </div>
 
        </div>
        <div class="page">
            @RenderBody()
        </div>
        <div id="footer">
            <p>&copy;@DateTime.Now.Year - DHTMLX Scheduler .NET</p>
        </div>
        <style type="text/css">
            /*for month events----------*/
            .state_1 {
                background-color: #5B9BE0;
            }
 
            .state_2 {
                background-color: #FE7510;
            }
 
            .state_3 {
                background-color: #76B007;
            }
</style>   <script type="text/javascript">
            scheduler.templates.event_class = function (start, end, ev) {
                return "state_" + ev.status_id;
            }
</script> </body>     </html>
  • UserControl

1 . Inside of the Shared folder create a file with the name UserControl.cshtml

2 . Delete the existing code from the opened file and paste the following code instead:

@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated)
{
    using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
    {
        @Html.AntiForgeryToken()
 
        <ul class="hr">
            <li>
               <a>Welcome  @User.Identity.GetUserName() !</a>
            </li>
            <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
        </ul>
    }
}
else
{
    <ul class="hr">
        <li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
        <li>@Html.ActionLink("Log in", "LogOn", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
    </ul>
}

2 . Account

The Account folder contains pages for logging in and registering user accounts.

  • Inside of the Account folder create LogOn.cshtml and Register.cshtml files
  • Paste the following code into LogOn.cshtml
@model TaskManager.MVC5.Models.LogOnModel
@{
    ViewBag.Title = "Log in";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<div id="loginContent" class="row">
    <p>Please enter your username and password.</p>
 
    <ul>
        <li>Manager/password</li>
        <li>David/password</li>
        <li>Dana/password</li>
        <li>Linda/password</li>
        <li>John/password</li>
    </ul>
    @using (Html.BeginForm("LogOn", "Account"))
    {
        @Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")
        <div class="center-block ">
            <div class="form-group">
                <div class="editor-label">
                    @Html.LabelFor(m => m.UserName)
                </div>
                <div class="editor-field">
                    @Html.TextBoxFor(m => m.UserName, new { @class = "dhx_cal_ltext" })
                    @Html.ValidationMessageFor(m => m.UserName)
                </div>
            </div>
 
            <div class="form-group">
                <div class="editor-label">
                    @Html.LabelFor(m => m.Password)
                </div>
                <div class="editor-field">
                    @Html.TextBoxFor(m => m.Password, new { @type = "password", @class = "dhx_cal_ltext" })
                    @Html.ValidationMessageFor(m => m.Password)
                </div>
            </div>
 
            <div class="editor-label form-group">
                @Html.CheckBoxFor(m => m.RememberMe)
                @Html.LabelFor(m => m.RememberMe)
            </div>
 
            <div class="form-group">
                <input type="submit" name="result" value="Log in" class="dhx_btn_set dhx_left_btn_set dhx_save_btn_set" style="width: 70px; float: right;" />
            </div>
        </div>
    }
</div>
  • Paste the following code to Register.cshtml:
@model TaskManager.MVC5.Models.RegisterModel
@{
    ViewBag.Title = "Register";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
@using (Html.BeginForm("Register", "Account"))
{
    <div class="center-block ">
 
        <div class="form-group">
            <div class="editor-label">
                @Html.LabelFor(m => m.UserName)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.UserName)
                @Html.ValidationMessageFor(m => m.UserName)
            </div>
        </div>
 
        <div class="form-group">
            <div class="editor-label">
                @Html.LabelFor(m => m.Email)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.Email)
                @Html.ValidationMessageFor(m => m.Email)
            </div>
        </div>
 
        <div class="form-group">
            <div class="editor-label">
                @Html.LabelFor(m => m.Password)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.Password, new { @type = "password" })
                @Html.ValidationMessageFor(m => m.Password)
            </div>
        </div>
 
        <div class="form-group">
            <div class="editor-label">
                @Html.LabelFor(m => m.ConfirmPassword)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.ConfirmPassword, new { @type = "password" })
                @Html.ValidationMessageFor(m => m.ConfirmPassword)
            </div>
        </div>
        <div class="form-group">
            <input type="submit" name="result" value="Register" class="dhx_btn_set dhx_left_btn_set dhx_save_btn_set" style="width: 70px; float: right;" />
        </div>
    </div>
}

3 . System

This folder has the following structure:

  • manager.cshtml file which represents the Manager page of the application.
  • employee.cshtml file represents Employee page.
  • TaskDetails.cshtml file displays task details data for employees.

1) Employee

  • Inside of the System folder Add a View named Employee.cshtml
  • Paste the following code:
@{
    ViewBag.Title = "Employee";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@Html.Raw(Model.Render())
<div id="footer-top-border"></div>
<script>
 
    scheduler.attachEvent("onClick", function (id) {
        window.location = '@Url.Action("TaskDetails","System")?id=' + id;
    });
</script>

The Employee page will look like this:

calendar agenda

2) Manager

  • In the System folder add a view named Manager.cshtml
  • Update the code as follows:
@model TaskManager.MVC5.Controllers.SystemController.SystemModel
@{
    ViewBag.Title = "Manage Tasks";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
@Html.Raw(Model.Scheduler.Render())
<div id="footer-top-border"></div>
<style type="text/css">
    @foreach(var state in Model.Statuses) {
        <text> .dhx_cal_event.state_@state.id div{
            background-color: @state.color;
        }
        </text>
    }
</style>
 
<script type="text/javascript">
    var data = JSON.parse('@Html.Raw(Model.Users)');
    scheduler.templates.event_header = function (start, end, ev) {
        return scheduler.templates.event_date(start) + " - " + scheduler.templates.event_date(end) + " (" + findById(data, ev.owner_id) + ")";
    };
 
    function findById(ar, id) {
        for (var i = 0; i < ar.length; i++) {
            if (ar[i].key == id) {
                return ar[i].userName;
            }
        }
        return "";
    }
</script>

The resulting Manager page is presented below:

staff calendar

3) TaskDetails

In the System folder add a View named TaskDetails.cshtml

Paste the following code into the created file:

@{
    ViewBag.Title = "TaskDetails";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@model TaskManager.MVC5.Models.TaskDetails
 
<div class="page row">
 
    <span>@ViewData["user"], TaskDetails</span>
 
 
    @if (Model.Task != null)
    {
        using (Html.BeginForm("Index", "System/UpdateStatus", FormMethod.Post, null))
        {
            @Html.Hidden("id", Model.Task.id)
 
            <div class="center-block">
                <div class=" text-right form-group">
                    <span>
 
                        @String.Format("{0:MM/dd/yyyy}", Model.Task.start_date),
                        <b>
                            @String.Format("{0:HH:mm}", Model.Task.start_date)
                            &ndash; @String.Format("{0:HH:mm}", Model.Task.end_date)
                        </b>
                    </span>
                </div>
                <div class="text-left dhx_cal_ltext form-group">
                    <h1>@Model.Task.text</h1>
                </div>
                <div class="text-left details form-group">
                    <div @( string.IsNullOrEmpty(Model.Task.details) ? "style= 'color':#bbb;" : "") style="word-wrap: break-word;">@(string.IsNullOrEmpty(Model.Task.details) ? "Task has no description" : Model.Task.details)</div>
                </div>
                <div class="text-left form-group">
                    <span>Status: </span>
                    @Html.DropDownList("status_id", new SelectList(Model.Statuses, "id", "title", ViewData["status"]), new
                    {
                        @class = "dhx_cal_ltext",
                        @style = "width:172px;"
                    })
                </div>
 
                <div class=" text-center form-group">
                    <input type="submit" name="result" value="Update"
                    class="dhx_btn_set dhx_left_btn_set dhx_save_btn_set" style="width: 70px;" />
 
                    <input type="submit" name="result" value="Cancel"
                    class="dhx_btn_set dhx_right_btn_set dhx_delete_btn_set" style="float: right; width: 70px;" />
                </div>
            </div>
 
        }
    }
 
</div>

Below you can see how the task details are displayed for employees:

task status

Step 4.7 Adding Controllers

1 . Inside of the Controllers folder Add → Empty Controllers named Account and System

2 . The AccountController contains action methods for log in and registration. Update AccountController.cs as follows:

using System.Threading.Tasks;
using System.Web.Mvc;
using Scheduler.MVC5.Users;
using TaskManager.MVC5.Models;
 
namespace TaskManager.MVC5.Controllers
{
    public class AccountController : Controller
    {
 
        #region sign in helper
        //get the SignInHelper object during an MVC controller execution 
        private SignInHelper _helper;
 
        private SignInHelper SignInHelper
        {
            get { return _helper ?? (_helper = new SignInHelper(AppUserManagerProvider.GetAppUserManager, AppUserManagerProvider.AuthenticationManager)); }
        }
        #endregion
 
        public AccountController(){}
 
        public AccountController(AppUserManager userManager)
        {
            AppUserManagerProvider.GetAppUserManager = userManager;
        }
 
        [HttpGet]
        public ActionResult LogOn()
        {
            return View();
        }
 
        [HttpPost]
        public async Task<ActionResult> LogOn(LogOnModel model, string returnUrl)
        {
            if (!ModelState.IsValid) return View(model);
            //Sign in if a model is valid
            var result = await SignInHelper.PasswordSignIn(model.UserName, model.Password, model.RememberMe);
 
            switch (result)
            {
                case "Success":
                {
                    return RedirectToAction("Index", "System");
                }
                default:
                {
                    ModelState.AddModelError("", "The user name or password is incorrect.");
 
                }break;
 
            }
            //if something failed, redisplay form
            return View(model);
        }
 
        public ActionResult LogOff()
        {
            AppUserManagerProvider.AuthenticationManager.SignOut();
            return RedirectToAction("LogOn", "Account");
        }
 
        public ActionResult Register()
        {
            return View();
        }
 
        [HttpPost]
        public async Task<ActionResult> Register(RegisterModel model)
        {
            if (!ModelState.IsValid) return View(model);
            //if a model is valid,create a user with credentials
            var user = new ApplicationUser {UserName = model.UserName, Email = model.Email};
            var result = await AppUserManagerProvider.GetAppUserManager.CreateAsync(user, model.Password);
 
            if (result.Succeeded)
            {
                //add default role for a new user
                await AppUserManagerProvider.GetAppUserManager.AddToRoleAsync(user.Id, "Employee");
                //sign in
                await SignInHelper.SignInAsync(user, isPersistent: true, rememderBrowser: false);
                return RedirectToAction("Index", "System");
            }
 
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError("", error);
            }
            //if something failed, redisplay form
            return View(model);
        }
    }
}

3 . Update SystemController as it is shown below:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Web.Mvc;
using DHTMLX.Common;
using DHTMLX.Scheduler;
using DHTMLX.Scheduler.Authentication;
using DHTMLX.Scheduler.Controls;
using DHTMLX.Scheduler.Data;
 
using Scheduler.MVC5.Users;
using TaskManager.MVC5.Model;
using TaskManager.MVC5.Models;
using System.Runtime.Serialization.Json;
 
namespace TaskManager.MVC5.Controllers
{
    public class SystemController : Controller
    {
        private IRepository _repository;
        private AppUserManagerProvider _appUserManagerProvider;
        public IRepository Repository
        {
            get { return _repository ?? (_repository = new Repository()); }
        }
 
        public AppUserManagerProvider AppUserManagerProvider
        {
            get { return _appUserManagerProvider ?? (_appUserManagerProvider = new AppUserManagerProvider()); }
        }
 
 
 
        // GET: System
        public ActionResult Index()
        {
            //redirect to login page unauthorized user
            return !Request.IsAuthenticated ? RedirectToAction("LogOn", "Account") : RedirectToAction(User.IsInRole("Manager") ? "Manager" : "Employee", "System");
        }
 
        public ActionResult Manager()
        {
            var scheduler = new DHXScheduler(this);
 
            #region check rights
            if (!RoleIs("Manager"))// checks the role
                return RedirectToAction("Index", "System");//in case the role is not manager, redirects to the login page
 
            #endregion
 
            #region configuration
 
            scheduler.Config.first_hour = 8;//sets the minimum value for the hour scale (Y-Axis)
            scheduler.Config.hour_size_px = 88;
            scheduler.Config.last_hour = 17;//sets the maximum value for the hour scale (Y-Axis)
            scheduler.Config.time_step = 30;//sets the scale interval for the time selector in the lightbox. 
            scheduler.Config.full_day = true;// blocks entry fields in the 'Time period' section of the lightbox and sets time period to a full day from 00.00 the current cell date until 00.00 next day. 
 
            scheduler.Skin = DHXScheduler.Skins.Flat;
            scheduler.Config.separate_short_events = true;
 
            scheduler.Extensions.Add(SchedulerExtensions.Extension.ActiveLinks);
 
            #endregion
 
            #region views configuration
            scheduler.Views.Clear();//removes all views from the scheduler
            scheduler.Views.Add(new WeekView());// adds a tab with the week view
            var units = new UnitsView("staff", "owner_id") { Label = "Staff" };// initializes the units view
 
            var users = AppUserManagerProvider.Users;
            var staff = new List<object>();
            foreach (var user in users)
            {
                if (AppUserManagerProvider.GetUserRolesName(user.Id).Contains("Employee"))
                {
                    staff.Add(new { key = user.Id, label = user.UserName });
                }
            }
 
            units.AddOptions(staff);// sets X-Axis items to names of employees  
            scheduler.Views.Add(units);//adds a tab with the units view
            scheduler.Views.Add(new MonthView()); // adds a tab with the Month view
            scheduler.InitialView = units.Name;// makes the units view selected initially
 
            scheduler.Config.active_link_view = units.Name;
            #endregion
 
            #region lightbox configuration
            var text = new LightboxText("text", "Task") { Height = 20, Focus = true };// initializes a text input with the label 'Task'
            scheduler.Lightbox.Add(text);// adds the control to the lightbox
            var description = new LightboxText("details", "Details") { Height = 80 };// initializes a text input with the label 'Task'
            scheduler.Lightbox.Add(description);
            var status = new LightboxSelect("status_id", "Status");// initializes a dropdown list with the label 'Status'
            status.AddOptions(Repository.GetAll<Status>().Select(s => new
            {
                key = s.id,
                label = s.title
            }));// populates the list with values from the 'Statuses' table
            scheduler.Lightbox.Add(status);
            //add users list 
            var sUser = new LightboxSelect("owner_id", "Employee");
            sUser.AddOptions(staff);
            //--
            scheduler.Lightbox.Add(sUser);
 
            scheduler.Lightbox.Add(new LightboxTime("time"));// initializes and adds a control area for setting start and end times of a task
            #endregion
 
            #region data
            scheduler.EnableDataprocessor = true;// enables dataprocessor
            scheduler.LoadData = true;//'says' to send data request after scheduler initialization 
            scheduler.Data.DataProcessor.UpdateFieldsAfterSave = true;// Tracks after server responses for modified event fields 
            #endregion
 
            Employees[] employees = users.Select(o => new Employees()
            {
                key = o.Id,
                userName = o.UserName
            }).ToArray();
 
            List<Status> statuses = Repository.GetAll<Status>().ToList();
 
            var js = new DataContractJsonSerializer(typeof(Employees[]));
            var ms = new MemoryStream();
            js.WriteObject(ms, employees);
            ms.Position = 0;
            var sr = new StreamReader(ms);
            var json = sr.ReadToEnd();
            sr.Close();
            ms.Close();
            var model = new SystemModel(scheduler, json,statuses);
            return View(model);
        }
 
        private bool RoleIs(string role)
        {
            return Request.IsAuthenticated && User.IsInRole(role);
        }
 
        public ActionResult Employee()
        {
            var scheduler = new DHXScheduler(this);
 
            #region check rights
            if (!RoleIs("Employee"))
            {
                return RedirectToAction("Index", "System");
            }
            #endregion
 
            #region configuration
 
            scheduler.Config.separate_short_events = true;
            scheduler.Config.hour_size_px = 88;
 
            scheduler.Extensions.Add(SchedulerExtensions.Extension.Cookie);// activates the extension to provide cookie
            scheduler.Extensions.Add(SchedulerExtensions.Extension.Tooltip);// activates the extension to provide tooltips
            var template = "<b>Task:</b> {text}<br/><b>Start date:</b>";
            template += "<%= scheduler.templates.tooltip_date_format(start) %><br/><b>End date:</b>";
            template += "<%= scheduler.templates.tooltip_date_format(end) %>";
            scheduler.Templates.tooltip_text = template; // sets template for the tooltip text
 
            scheduler.Skin = DHXScheduler.Skins.Flat;
            #endregion
 
            #region views
            scheduler.Views.Clear();//removes all views from the scheduler 
            scheduler.Views.Add(new WeekAgendaView());// adds a tab with the weekAgenda view
            scheduler.Views.Add(new MonthView()); // adds a tab with the Month view
            scheduler.InitialView = scheduler.Views[0].Name;// makes the weekAgenda view selected initially
            #endregion
 
            #region data
            scheduler.SetEditMode(EditModes.Forbid);// forbids editing of tasks  
            scheduler.LoadData = true;//'says' to send data request after scheduler initialization 
            scheduler.DataAction = "Tasks";//sets a controller action which will be called for data requests 
            scheduler.Data.Loader.PreventCache();// adds the current ticks value to url to prevent caching of the request 
            #endregion
 
            return View(scheduler);
        }
 
 
        public ActionResult Data()
        {
            //if the user is not authorized or not in the Manager Role, returns the empty dataset
            if (!RoleIs("Manager")) return new SchedulerAjaxData();
 
            var tasks = Repository.GetAll<Task>()
                .Join(Repository.GetAll<Status>(), task => task.status_id, status => status.id, (task, status) => new { Task = task, Status = status })
                .Select(o => new
                {
                    o.Status.color,
                    o.Task.id,
                    o.Task.owner_id,
                    o.Task.details,
                    o.Task.end_date,
                    o.Task.start_date,
                    o.Task.text,
                    o.Task.status_id
                });
 
            var resp = new SchedulerAjaxData(tasks);
            return resp;
 
        }
        public ActionResult Save(Task task)
        {
            // an action against particular task (updated/deleted/created) 
            var action = new DataAction(Request.Form);
            #region check rights
            if (!RoleIs("Manager"))
            {
                action.Type = DataActionTypes.Error;
                return new AjaxSaveResponse(action);
            }
            #endregion
 
            task.creator_id = Guid.Parse(AppUserManagerProvider.UserId);
            try
            {
                switch (action.Type)
                {
                    case DataActionTypes.Insert:
                        Repository.Insert(task);
                        break;
                    case DataActionTypes.Delete:
                        Repository.Delete(task);
                        break;
                    case DataActionTypes.Update:
                        Repository.Update(task);
                        break;
                }
                action.TargetId = task.id;
            }
            catch (Exception)
            {
                action.Type = DataActionTypes.Error;
            }
 
            var color = Repository.GetAll<Status>().SingleOrDefault(s => s.id == task.status_id);
 
            var result = new AjaxSaveResponse(action);
            result.UpdateField("color", color.color);
            return result;
        }
 
        public ActionResult Tasks()
        {
            #region check rights
            if (!RoleIs("Employee"))
            {
                return new SchedulerAjaxData();//returns the empty dataset
            }
            #endregion
 
 
            var result = Repository.GetAll<Task>()
                .Join(Repository.GetAll<Status>(), task => task.status_id, status => status.id, (task, status) => new { Task = task, Status = status })
                .Select(o => new
                {
                    o.Status.color,
                    o.Task.id,
                    o.Task.owner_id,
                    o.Task.details,
                    o.Task.end_date,
                    o.Task.start_date,
                    o.Task.text,
                    o.Task.status_id
                });
 
            var tasks = new List<object>();
 
            foreach (var r in result.ToList())
            {
                if (r.owner_id == Guid.Parse(AppUserManagerProvider.UserId))
                {
                    tasks.Add(new
                    {
                        r.color,
                        r.id,
                        r.owner_id,
                        r.details,
                        r.end_date,
                        r.start_date,
                        r.text,
                        r.status_id
                    });
                }
            }
 
            var resp = new SchedulerAjaxData(tasks);
            return resp;
        }
 
        public ActionResult TaskDetails(int? id)
        {
            #region check rights
 
            if (!RoleIs("Employee"))
            {
                return RedirectToAction("Index", "System");
            }
            #endregion
 
            var task = default(Task);
            if (id != null)
            {
                task = Repository.GetAll<Task>().FirstOrDefault(o => o.id == id);
 
                if (task.owner_id != Guid.Parse(AppUserManagerProvider.UserId))
                    task = default(Task);
            }
 
            var statuses = Repository.GetAll<Status>().ToArray();
 
            ViewData["status"] = task != default(Task) ? task.status_id : statuses[0].id;
            ViewData["user"] = User.Identity.Name;
            return View(new TaskDetails(task, statuses));
        }
 
        public ActionResult UpdateStatus(int? id)
        {
            if (!RoleIs("Employee") || this.Request.Form["result"] != "Update" || id == null)
                return RedirectToAction("Index", "System");
 
 
            var task = Repository.GetAll<Task>().SingleOrDefault(ev => ev.id == id);
 
            if (task == default(Task) && task.owner_id != Guid.Parse(AppUserManagerProvider.UserId))
                return RedirectToAction("Index", "System");
 
            task.status_id = int.Parse(this.Request.Form["status_id"]);
            UpdateModel(task);
            Repository.Update(task);
 
            return RedirectToAction("Index", "System");
        }
 
        public class SystemModel
        {
            public DHXScheduler Scheduler { get; set; }
            public string Users { get; set; }
            public List<Status> Statuses { get; set; }
            public SystemModel(DHXScheduler sched, string users,List<Status> statuses )
            {
                Scheduler = sched;
                Users = users;
                Statuses = statuses;
            }
        }
 
 
        //class for JSON string
        [DataContract]
        public class Employees
        {
            [DataMember]
            public string key { get; set; }
            [DataMember]
            public string userName { get; set; }
        }
    }
}

The controller file in our application SystemController.cs defines the following controls:

  • Index
  • Manager
  • Employee

In all the actions defined at this and further steps (except Index()), we will do 'rights checking' to protect the app from unauthorized access, in case a user skips the login page and loads our server-side login script directly in the browser.

To avoid repeating one and the same code several times, we'll also specify a function (RoleIs) that will implement such checking functionality and later, when we need to check rights, we'll just call this function.

Data ActionResult loads data from the database.

Save ActionResult saves changes to the database.

4 . Move to Solution ExplorerRouteConfig.cs file.

5 . Rewrite the default map route in the opened file as follows:

routes.MapRoute(
  "Default", // the route name
  "{controller}/{action}/{id}", // URL with parameters
  new { controller = "System", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

Step 4.8. Specifying Styles

1 . In the Content folder add a Style Sheet (create it, if it does not exist) and named it Site.css This file contains styles for all site.

2 . Paste the following code to the created file:

/*----------------------------------------------------------
The base color for this template is #5c87b2. If you'd like
to use a different color start by replacing all instances of
#5c87b2 with your new color.
----------------------------------------------------------*/
body {
    background-color: #ffffff;
    font-size: 14px;
    font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
    margin: 0;
    padding: 0;
    color: #000000;
}
 
a:link {
    color: #034af3;
    text-decoration: underline;
}
 
a:visited {
    color: #505abc;
}
 
a:hover {
    color: #1d60ff;
    text-decoration: none;
}
 
a:active {
    color: #12eb87;
}
 
p, ul {
    margin-bottom: 20px;
    line-height: 1.6em;
}
 
/* HEADINGS
----------------------------------------------------------*/
h1, h2, h3, h4, h5, h6 {
    font-size: 18px;
    color: #000;
    font-family: Arial, Helvetica, sans-serif;
}
 
h1 {
    font-size: 36px;
    padding-bottom: 0;
    margin-bottom: 0;
}
 
h2 {
    font-size: 30px;
    padding: 0 0 10px 0;
}
 
h3 {
    font-size: 24px;
}
 
h4 {
    font-size: 18em;
}
 
h5, h6 {
    font-size: 14em;
}
 
/* this rule styles <h2> tags that are the
first child of the left and right table columns */
.rightColumn > h1, .rightColumn > h2, .leftColumn > h1, .leftColumn > h2 {
    margin-top: 0;
}
/**/
body, html {
    height: 90%;
    margin: 0;
    padding: 0;
}
 
/* PRIMARY LAYOUT ELEMENTS
----------------------------------------------------------*/
 
/* you can specify a greater or lesser percentage for the
page width. Or, you can specify an exact pixel width. */
.page {
    height: 100%;
    margin-left: auto;
    margin-right: auto;
}
 
#header {
    position: relative;
    margin-bottom: 0px;
    color: #000;
    padding: 0;
    border-bottom: #5780AD 3px solid;
}
 
    #header h1 {
        font-weight: bold;
        padding: 5px 0;
        margin: 0;
        color: #fff;
        border: none;
        line-height: 2em;
        font-family: Arial, Helvetica, sans-serif;
    }
 
#main {
    padding: 30px 30px 15px 30px;
    background-color: #fff;
    margin-bottom: 30px;
    _height: 1px; /* only IE6 applies CSS properties starting with an underscore */
}
 
#footer {
    color: #000000;
    text-align: center;
    line-height: normal;
    bottom: 0;
    margin-bottom: 0;
}
 
#footer-top-border {
    border-top: 1px solid #CECECE;
}
 
/* FORM LAYOUT ELEMENTS
----------------------------------------------------------*/
 
fieldset {
    margin: 1em 0;
    padding: 1em;
    border: 1px solid #ffffff;
}
 
    fieldset p {
        margin: 2px 12px 10px 10px;
    }
 
 
 
input[type="text"] {
    width: 200px;
    border: 1px solid #CCC;
}
 
input[type="password"] {
    width: 200px;
    border: 1px solid #CCC;
}
 
 
/* MISC
----------------------------------------------------------*/
.clear {
    clear: both;
}
 
.error {
    color: Red;
}
 
#menucontainer {
    margin-top: 40px;
}
 
div#title {
    display: block;
    float: left;
    text-align: left;
}
 
#logindisplay {
    display: block;
    text-align: right;
    margin: 10px;
    color: #000000;
}
 
    #logindisplay a:link {
        color: #000000;
        text-decoration: underline;
    }
 
    #logindisplay a:visited {
        color: #000000;
        text-decoration: underline;
    }
 
    #logindisplay a:hover {
        color: #000000;
        text-decoration: none;
    }
 
/* Styles for validation helpers
-----------------------------------------------------------*/
.field-validation-error {
    color: #ff0000;
}
 
.field-validation-valid {
    display: none;
}
 
.input-validation-error {
    border: 1px solid #ff0000;
    background-color: #ffeeee;
}
 
.validation-summary-errors {
    font-weight: bold;
    color: #ff0000;
}
 
.validation-summary-valid {
    display: none;
}
 
/* Styles for editor and display helpers
----------------------------------------------------------*/
.display-label,
.editor-label,
.display-field,
.editor-field {
    margin: 0.5em 0;
}
 
.text-box {
    width: 30em;
}
 
    .text-box.multi-line {
        height: 6.5em;
    }
 
.tri-state {
    width: 6em;
}
/*horizontal list*/
ul.hr {
    margin: 0;
    padding: 4px;
}
 
    ul.hr li {
        display: inline;
        margin-right: 5px;
        padding: 3px;
    }
 
 
.center-block {
    width: 220px;
    padding: 10px;
    margin: 0 auto;
}
 
.row {
    margin-left: 15px;
    margin-right: 15px;
}
 
.text-left {
    text-align: left;
}
 
.text-center {
    text-align: center;
}
 
.text-right {
    text-align: right;
}
 
.form-group {
    margin-top: 10px;
    margin-bottom: 10px;
}
 
input[type="text"], input[type="password"], input[type="checkbox"] {
    padding: 7px 9px;
}
 
input[type="submit"].dhx_save_btn_set:hover {
    background-color: #528CCA;
}
 
input[type="submit"].dhx_save_btn_set:active {
    background-color: #6BA5E3;
}
 
 
input[type="submit"].dhx_delete_btn_set:hover {
    background-color: #CCCCCC;
}
 
input[type="submit"].dhx_delete_btn_set:active {
    background-color: #949494;
}
 
.details {
    white-space: pre;
    border: 1px solid #eeeeee;
    padding: 10px;
}
 
.form-bordered {
    border: 1px solid #eeeeee;
}
 
div.dhx_cal_ltext {
    height: 26px !important;
}
/*for month events----------*/
.dhx_cal_event_clear {
    padding: 2px 0 2px 5px !important;
    -ms-border-radius: 13px !important;
    border-radius: 13px !important;
    line-height: 14px !important;
    color: white !important;
}

That's all. You can download task manager sample in MVC5.

Was this article helpful?

Yes No