Kanban example with realistic 'professional' data.

I try to make a simple working Kanban example with realistic data.

By 'realistic' I mean using proper IDs as GUIDs instead of manually written strings, like 'Open' and 'Close'.

For example:

public partial class TaskStatus

{

    public TaskStatus(Guid id, string name, int orderNo, bool allowAddNewItem)

    {

        Id = id;

        Name = name;

        OrderNo = orderNo;

        AllowAddNewItem = allowAddNewItem;


        KanbanKeyFields = new List<string>();

        KanbanKeyFields.Add(Id.ToString());

    }


    [Key]

    public Guid Id { get; set; }


    [Required(AllowEmptyStrings = false)]

    public string Name { get; set; }


    public int OrderNo { get; set; }


    #region Nav - Task


    [InverseProperty(nameof(Task.Status))]

    public ICollection<Task> Tasks { get; set; }


    #endregion


    public bool IsFallback { get; set; }


    public bool AllowAddNewItem { get; set; }

}


public partial class TaskStatus

{



    [NotMapped]

    public List<string> KanbanKeyFields { get; set; }

    //{

    // get

    // {

    // var fields = new List<string>();

    // fields.Add(Name);

    // if (IsFallback)

    // fields.Add("");

    // return fields;

    // }

    //}

}

Meanwhile, the Task looks as follows:

public partial class Task

{

    [Key]

    public Guid Id { get; set; }


    [Required(AllowEmptyStrings = false)]

    public string Title { get; set; }


    [Required(AllowEmptyStrings = false)]

    public string Description { get; set; }


    public DateTime? DueAt { get; set; }


    #region Nav - Status


    public Guid StatusId { get; set; }


    [ForeignKey(nameof(StatusId))]

    public TaskStatus Status { get; set; }


    #endregion


    #region Nav - Assignes


    [InverseProperty(nameof(TaskUser.Task))]

    public virtual ICollection<TaskUser> Assignees { get; set; }


    #endregion

}


public partial class Task

{

    [NotMapped]

    public string StatusIdString => StatusId.ToString();


    //[NotMapped]

    //public string StatusName

    //{

    // get

    // {

    // if (Status is null)

    // return "";


    // return Status.Name;

    // }

    //}

}


Where the Keyfield is the  StatusIdString (because it only accepts string for some reason...)

KeyField="@nameof(Task.StatusIdString)"

The Kanban columns are populated as:

          <KanbanColumns>

              @foreach (var status in TaskStatuses)

              {

                  <KanbanColumn HeaderText="@status.Name"

                                KeyField="@status.KanbanKeyFields"

                                AllowAdding="@status.AllowAddNewItem"

                                Visible="true"

                                IsExpanded="true"

                                AllowToggle="true" />

              }

          </KanbanColumns>


Please show me a working example, based on the given data model.


1 Reply

PK Priyanka Karthikeyan Syncfusion Team May 13, 2025 02:57 PM UTC

Hi Istvan Piroska,


Sorry for the delay in response. We have updated the Kanban sample to use realistic GUID-based data for TaskStatus.Id. Since the Kanban KeyField only accepts strings, we used a StatusIdString property in the Task model to convert the GUID to a string. Similarly, we populated the KanbanKeyFields list in TaskStatus with the string version of the ID to bind it correctly in each KanbanColumn. The Kanban component is now fully functional with this setup.

 

Index.razor

 

 

@page "/"

@using Syncfusion.Blazor.Kanban

@using System.ComponentModel.DataAnnotations

@using System.ComponentModel.DataAnnotations.Schema

 

<SfKanban TValue="Task"

          KeyField="@nameof(Task.StatusIdString)"

          DataSource="@Tasks">

    <KanbanColumns>

        @foreach (var status in TaskStatuses.OrderBy(s => s.OrderNo))

        {

            <KanbanColumn HeaderText="@status.Name"

                          KeyField="@status.KanbanKeyFields"

                          AllowAdding="@status.AllowAddNewItem"

                          IsExpanded="true"

                          AllowToggle="true" />

        }

    </KanbanColumns>

 

    <KanbanCardSettings HeaderField="@nameof(Task.Title)"

                        ContentField="@nameof(Task.Description)">

    </KanbanCardSettings>

</SfKanban>

 

@code {

    // Sample statuses

    private List<TaskStatus> TaskStatuses = new()

    {

        new TaskStatus(Guid.Parse("3f2504e0-4f89-11d3-9a0c-0305e82c3301"), "To Do", 1, true),

        new TaskStatus(Guid.Parse("3f2504e0-4f89-11d3-9a0c-0305e82c3302"), "In Progress", 2, true),

        new TaskStatus(Guid.Parse("3f2504e0-4f89-11d3-9a0c-0305e82c3303"), "Review", 3, false),

        new TaskStatus(Guid.Parse("3f2504e0-4f89-11d3-9a0c-0305e82c3304"), "Done", 4, false)

    };

 

    // Sample tasks

    private List<Task> Tasks => new()

    {

        new Task

        {

            Id = Guid.NewGuid(),

            Title = "Design Database Schema",

            Description = "Create ER diagrams and normalize the database.",

            StatusId = TaskStatuses[0].Id,

            Status = TaskStatuses[0]

        },

        new Task

        {

            Id = Guid.NewGuid(),

            Title = "Implement Login Flow",

            Description = "Implement login, logout and token refresh features.",

            StatusId = TaskStatuses[1].Id,

            Status = TaskStatuses[1]

        },

        new Task

        {

            Id = Guid.NewGuid(),

            Title = "Review PR #42",

            Description = "Code review for the latest pull request.",

            StatusId = TaskStatuses[2].Id,

            Status = TaskStatuses[2]

        },

        new Task

        {

            Id = Guid.NewGuid(),

            Title = "Deploy to Production",

            Description = "Final deployment of version 1.0.",

            StatusId = TaskStatuses[3].Id,

            Status = TaskStatuses[3]

        }

    };

}

 

 

 

TaskStatus.cs

 

 

 public partial class TaskStatus

{

    public TaskStatus(Guid id, string name, int orderNo, bool allowAddNewItem)

    {

        Id = id;

        Name = name;

        OrderNo = orderNo;

        AllowAddNewItem = allowAddNewItem;

        KanbanKeyFields = new List<string> { Id.ToString() };

    }

 

    [Key]

    public Guid Id { get; set; }

 

    [Required(AllowEmptyStrings = false)]

    public string Name { get; set; }

 

    public int OrderNo { get; set; }

    public bool AllowAddNewItem { get; set; }

    public bool IsFallback { get; set; }

 

    [InverseProperty(nameof(Task.Status))]

    public ICollection<Task> Tasks { get; set; }

 

    [NotMapped]

    public List<string> KanbanKeyFields { get; set; }

}

 

 

Task.cs

 

 

public partial class Task

{

    [Key]

    public Guid Id { get; set; }

 

    [Required(AllowEmptyStrings = false)]

    public string Title { get; set; }

 

    [Required(AllowEmptyStrings = false)]

    public string Description { get; set; }

 

    public DateTime? DueAt { get; set; }

 

    public Guid StatusId { get; set; }

 

    [ForeignKey(nameof(StatusId))]

    public TaskStatus Status { get; set; }

 

    // [InverseProperty(nameof(TaskUser.Task))]

    // public virtual ICollection<TaskUser> Assignees { get; set; }

 

    [NotMapped]

    public string StatusIdString => StatusId.ToString();

}

 Sample: https://blazorplayground.syncfusion.com/embed/BjLoNIWqSKnwKbcJ?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5

 

Regards,

Priyanka K


Loader.
Up arrow icon