Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
152040 stories
·
33 followers

Why PDF Creation Belongs at the End of the Business Process

1 Share
This article discusses why placing PDF creation at the end of the business process is important for ensuring accuracy and efficiency. The most scalable systems delay PDF generation until the document has reached the end of its lifecycle.

Read the whole story
alvinashcraft
42 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Build a Modern Student Enrollment Dashboard Using .NET MAUI Charts

1 Share

Build a Modern Student Enrollment Dashboard Using .NET MAUI Charts

TL;DR: Learn how to build a modern, responsive Student Enrollment Dashboard in .NET MAUI using Syncfusion Charts, Gauges, and Inputs. Visualize KPIs like admission count, gender distribution, program breakdown, and regional student mix with interactive charts.

Welcome to our Chart of the Week series!

Universities deal with thousands of rows of enrollment data, but spreadsheets rarely tell the full story. That’s where dashboards shine, turning raw numbers into actionable insights.

In this guide, we’ll build a Student Enrollment Dashboard in .NET MAUI using Syncfusion® .NET MAUI Charts. The goal? Transform admissions data into a responsive, visually engaging experience that works across devices.

Why this Dashboard matters

Every tile in the dashboard offers a unique perspective on enrollment health, filled seats, gender diversity, program breakdowns, and international reach. Admissions teams can track progress, identify trends, and make data-driven decisions instantly. It includes:

  • Degree filter for dynamic segmentation.
  • Admission KPI gauge showing filled vs. total seats.
  • Notice banner for seat availability and deadlines.
  • Gender distribution Doughnut chart.
  • A Sunburst chart for program breakdown (Degree → Course → Program Type).
  • A Column chart for student count by country/region.
  • Responsive layout optimized for desktops and mobile.

The core goals are:

  • Monitor enrollment targets.
  • Visualize gender and regional diversity.
  • Highlight program popularity and capacity.
  • Enable data-driven decisions for outreach and scheduling.
Visualizing a Student Enrollment Dashboard using .NET MAUI Charts
Visualizing a Student Enrollment Dashboard using .NET MAUI Charts

Step 1: Create the Model and ViewModel

Begin by defining the classes that structure your data and manage business logic. These models form the backbone of the dashboard, ensuring that well-organized data drives each visualization.

Refer to the code example below.

public class DegreeModel
{
    // Represents a single academic degree (e.g., Medical, Engineering, Arts & Science).
    // Used to drive the degree filter, admission KPI gauge, notice banner, gender chart, and region chart.
}

public class CountryStat
{
    // Holds information about student counts by country or region.
    // Drives the Students by Country/Region column chart visualization.
}

public class ProgramType
{
    // Represents a specific program type under a course.
    // Used in the Sunburst chart to show distribution of students by program type.
}

public class CourseModel
{
    // Represents a course under a degree (e.g., AI, Civil, Neuro).
    // Drives the middle ring of the Sunburst chart and aggregates program type data.
}

public class GenderStat
{
    // Holds gender distribution data (e.g., Male, Female, Other).
    // Drives the Gender Distribution doughnut chart visualization.
}

public class SunburstNode
{
    // Represents hierarchical data for the Sunburst chart:
    // Degree → Course → ProgramType with associated student count.
}

Next, create the EnrollmentViewModel, which binds these models to the UI.

public partial class EnrollmentViewModel 
{
    // Selected degree drives all dashboard tiles
    public DegreeModel? SelectedDegree {get; set;}
    // KPI Gauge bindings
    public int GaugeTotal  {get; set;}
    public double GaugeShapePointer  {get; set;}
    public string AdmittedSeatsByDegree  {get; set;}
    public int RemainingVacancies  {get; set;}

    // Notice banner deadline
    public string ApplicationCloseText {get; set;}

    // Collections bound to UI
    public ObservableCollection<DegreeModel> Degrees { get; }
    public IList<SunburstNode> SunburstData { get; }
    public List<Brush> CustomBrushes { get; set; }
    public IList<GenderStat> GenderStats => SelectedDegree?.Gender ?? new List<GenderStat>();
    public IList<CountryStat> CountryStats => SelectedDegree?.Countries ?? new List<CountryStat>();

    // Constructor initializes static data and palettes
    public EnrollmentViewModel()
    {
        Degrees = new ObservableCollection<DegreeModel>(CreateStaticDegrees());
        SelectedDegree = Degrees.First(d => d.Name == "Medical");
        SunburstData = BuildSunburst(Degrees);
    }

    private IEnumerable<DegreeModel> CreateStaticDegrees()
    {
        // Generates the static dataset of degree, course, gender, and country stats for the dashboard.
    }

    private IList<SunburstNode> BuildSunburst(IEnumerable<DegreeModel> degrees)
    {
        // Builds hierarchical nodes (Degree → Course → ProgramType) for the Sunburst chart visualization.
    }
}

Note: You can view the complete code implementation in the Model and EnrollmentViewModel classes.

Step 2: Configure the layout

Once the data structure is ready, the next step is to design the dashboard layout. A clean and responsive layout ensures that insights are easy to interpret.

We’ll use a MainGrid divided into three rows:

  • Header row: Branded title and degree filter.
  • Middle row: KPI gauge, notice banner, and gender chart.
  • Bottom row: Sunburst chart and regional column chart.

Here’s how you can do it in XAML code:

<!--MainGrid-->   
<Grid x:Name="MainGrid" RowDefinitions="{OnPlatform Default='0.6*,4.2*,5*',  Android='2*,440,5*', iOS='2*,440,5*'}" >

    <Grid Grid.Row="1" ColumnDefinitions="{OnPlatform Default='*,auto', Android='*',iOS='*'}" RowDefinitions="{OnPlatform Default='*',Android='*,*',iOS='*,*'}">

        <!--Title-->
        <Grid ColumnDefinitions="Auto,*" >
            …
        </Grid>

        <!--ComboBox-->
        <Border Grid.Row="1" Grid.Column="1">
            …
        </Border>
    </Grid>

    <!--AdmissionData, NoticeData, GenderData-->
    <Grid Grid.Row="1" ColumnDefinitions="{OnPlatform Default='*',WinUI='*,*',MacCatalyst='*,*'}" >

        <Grid Grid.Column="0" RowDefinitions="{OnPlatform Default='*', Android='*,*',iOS='*,*'}" ColumnDefinitions="{OnPlatform Default='*', WinUI='6*,4*', MacCatalyst='6*,4*'}">
            …
        </Grid>
    </Grid>

    <!--OverallData, RegionData-->
    <Grid Grid.Row="2" ColumnDefinitions="{OnPlatform Default='*',WinUI='*,*',MacCatalyst='*,*'}" RowDefinitions="{OnPlatform Default='*', Android='*,*',iOS='*,*'}">
        …
    </Grid>
</Grid>

Step 3: Degree filter with branded header

After setting up the layout, focus on the header section. This area establishes the dashboard’s identity and provides an interactive degree filter.

Using SfComboBox, users can quickly switch between programs such as Medical, Engineering, and Arts. Each selection triggers dynamic updates across all charts, ensuring real-time insights.

Step 4: Admission KPI Gauge

Now that users can filter by degree, it’s time to visualize seat occupancy. The KPI gauge answers the critical question: How many seats are filled?

Powered by SfRadialGauge, this component delivers an intuitive radial chart with smooth animations and bold annotations. As the needle moves, users instantly see progress toward enrollment goals.

Key features:

Here’s the complete XAML code block.

<Border>
    <Grid RowDefinitions="Auto,*">
        <Label  Text="Admission Count Details"/>

        <sfGauge:SfRadialGauge   Grid.Row="1">
            <sfGauge:SfRadialGauge.Axes>
                <sfGauge:RadialAxis Minimum="0" Maximum="{Binding SelectedDegree.TotalSeats}"/>
                    <sfGauge:RadialAxis.AxisLineStyle>
                        <sfGauge:RadialLineStyle CornerStyle="BothCurve"/>
                    </sfGauge:RadialAxis.AxisLineStyle>
                    …
                    <sfGauge:RadialAxis.Annotations>
                        <sfGauge:GaugeAnnotation>
                            <sfGauge:GaugeAnnotation.Content>
                                ...
                            </sfGauge:GaugeAnnotation.Content>
                        </sfGauge:GaugeAnnotation>
                    </sfGauge:RadialAxis.Annotations>
                    <sfGauge:RadialAxis.Pointers>
                        …
                    </sfGauge:RadialAxis.Pointers>
                </sfGauge:RadialAxis>
            </sfGauge:SfRadialGauge.Axes>
        </sfGauge:SfRadialGauge>
    </Grid>
</Border>

Here’s what the Radial Gauge looks like:

Radial gauge chart in .NET MAUI displaying admission KPI
Radial gauge chart in .NET MAUI displaying admission KPI

Step 5: Display context with a Notice banner

Numbers alone don’t tell the full story. To provide context, add a notice banner that highlights seat availability and application deadlines. This card-style component keeps admissions teams informed and focused on key dates.

<Border x:Name="Banner" >
    <Grid VerticalOptions="{OnPlatform Default=Fill, MacCatalyst=Center}" RowDefinitions="auto,*" RowSpacing="{OnPlatform Default=14, MacCatalyst=18}" Padding="{OnPlatform Default=20, MacCatalyst=20 0 20 20}">

        <Image Source="graduate.png" HorizontalOptions="Start" VerticalOptions="Start" WidthRequest="60" HeightRequest="60"/>

        <VerticalStackLayout Grid.Row="1" Spacing="{OnPlatform Default=10, MacCatalyst=14}">

            <Label Text="{Binding SelectedDegree.Name, StringFormat='Degree: {0}'}" FontAttributes="Bold" FontSize="18" TextColor="#610097"/>

            <Label Text="{Binding RemainingVacancies, StringFormat='Available seats {0}'}" FontSize="16" TextColor="#1F2937"/>

            <Label Text="{Binding ApplicationCloseText}" FontSize="13" TextColor="#6B7280" LineBreakMode="WordWrap"/>
        </VerticalStackLayout>
    </Grid>
</Border>

Here’s the expected output:

Notice Banner in .NET MAUI showing seats and deadline
Notice Banner in .NET MAUI showing seats and deadline

Step 6: Visualizie Gender distribution with a Doughnut Chart

Now, showcase diversity using a gender distribution chart. Built with SfCircularChart and DoughnutSeries, this visualization updates dynamically based on the selected degree.

This chart highlights,

Here’s a code snippet to achieve this.

<Border>
    <Grid>
        <sfCharts:SfCircularChart>
            <sfCharts:DoughnutSeries  ItemsSource="{Binding GenderStats}" StartAngle=" EndAngle="360" XBindingPath="Category" YBindingPath="Count"/>
        </sfCharts:SfCircularChart>
    </Grid>
</Border>

After running the code, you’ll see this.

Doughnut Chart in .NET MAUI showing gender distribution

Step 7: Sunburst Chart for program distribution

After showcasing gender diversity, the next step is to explore the overall enrollment structure. To achieve this, we’ll use a Sunburst Chart, which provides an interactive and visually appealing way to represent hierarchical data.

This chart illustrates enrollment across various degrees, courses, and program types, enabling teams to quickly identify trends and popular programs. Think of it as a hierarchical tree reimagined as concentric rings:

  • The innermost ring represents degrees.
  • The middle ring expands into courses.
  • The outer ring displays program types.

With labels and interactive tooltips, users can drill down into the data to uncover which programs attract the most students and pinpoint areas with the strongest enrollment. This visualization makes complex relationships easy to interpret at a glance.

Below is the code you need to implement this feature.

<Border>
    <sfSunburst:SfSunburstChart ItemsSource="{Binding SunburstData}" ValueMemberPath="StudentCount" >

        <sfSunburst:SfSunburstChart.Levels>
            <sfSunburst:SunburstHierarchicalLevel GroupMemberPath="DegreeName"/>
            <sfSunburst:SunburstHierarchicalLevel GroupMemberPath="CourseName"/>
            <sfSunburst:SunburstHierarchicalLevel GroupMemberPath="ProgramType"/>
        </sfSunburst:SfSunburstChart.Levels>

    </sfSunburst:SfSunburstChart>
</Border>

The following image shows the Sunburst Chart.

Sunburst Chart in .NET MAUI showing program distribution
Sunburst Chart in .NET MAUI showing program distribution

Step 8: Visualize Students by Country/Region with a Column Chart

Finally, let’s highlight geographic diversity in enrollment. The Students by Country/Region tile provides a clear view of how student numbers vary across different countries. Each column represents a country, and its height reflects the number of students enrolled, making comparisons quick and intuitive.

This visualization is implemented using SfCartesianChart with a ColumnSeries, which binds directly to country-level statistics. As users switch between degrees, the chart updates dynamically to reflect the latest data. Rounded corners and smooth animated transitions give the chart a modern, polished look that feels approachable and professional.

Below is the code snippet you’ll need to create this feature:

<Border>
    <sfCharts:SfCartesianChart>
        <sfCharts:SfCartesianChart.XAxes>
            <sfCharts:CategoryAxis>
            </sfCharts:CategoryAxis>
        </sfCharts:SfCartesianChart.XAxes>

        <sfCharts:SfCartesianChart.YAxes>
            <sfCharts:NumericalAxis>
            </sfCharts:NumericalAxis>
        </sfCharts:SfCartesianChart.YAxes>

        <sfCharts:ColumnSeries  ItemsSource="{Binding CountryStats}" XBindingPath="Country" YBindingPath="Count"/>
    </sfCharts:SfCartesianChart>
</Border>
Column Chart in .NET MAUI showing country and region
Column Chart in .NET MAUI showing country and region

Implement these steps, and you’ll have a fully functional Student Enrollment Dashboard in .NET MAUI, as shown below.

Visualizing a Student Enrollment Dashboard using .NET MAUI Charts
Visualizing a Student Enrollment Dashboard using .NET MAUI Charts

GitHub reference

For more details, refer to the .NET MAUI Student Enrollment dashboards sample on GitHub.

Supercharge your cross-platform apps with Syncfusion's robust .NET MAUI controls.

Conclusion

Thank you for reading! In this guide, we explored how to create a Student Enrollment Dashboard using Syncfusion .NET MAUI Charts.

If you’re a Syncfusion user, you can download the setup from the license and downloads page. Otherwise, you can download a free 30-day trial.

You can also contact us through our support forumsupport portal, or feedback portal for queries. We are always happy to assist you!

Read the whole story
alvinashcraft
42 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Deterministic Voice Forms with Blazor and Local LLMs

1 Share
Deterministic Voice Forms with Blazor and Local LLMs
Read the whole story
alvinashcraft
42 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Top 13 Open-Source Automation Tools for 2026

1 Share
Discover 13 open-source automation tools for 2026 to streamline DevOps, cut manual work, and scale secure, reliable infrastructure.
Read the whole story
alvinashcraft
42 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

How can you swap two adjacent blocks of memory using only forward iterators?

1 Share

Last time, we noted that the std::rotate function requires only forward iterators. The algorithm we explored last time involved a clever sequence of reversals, but reversals require bidirectional iterators (one to iterator forward from the beginning and another to iterate backward from the end). How do you do it when you can only iterate forward?

Let’s set up the problem again. Suppose we want to swap these two blocks A and B.

A B  
first mid last

We can early-out in the vacuous cases where either the A or B block is empty. For those cases, we can return without doing anything.

We start by swapping the elements at first and mid, then incrementing both pointers and repeating. Here’s what it looks after swapping a handful of items:

B1 A2 A1 B2  
   
  first   mid last

Let’s first take the case where the A block is bigger than the B block. In that case, the entire B block gets swapped to the start of the buffer, and a B-sized chunk of the first part of the A block (let’s call it A1) got swapped to the end of the buffer. There’s still a leftover chunk of the A block, call it A2, that hasn’t moved yet.

B A2 A1  
   
  first   mid
last

Okay, so the B block is in its final position, but the A1 and A2 blocks need to be swapped. Hey, I know how to swap two adjacent blocks: I call std::rotate on myself recursively! Since this is a tail recursive call, I can just move mid back to its original position at the start of the function and restart the algorithm.

B A2 A1  
 
  first mid last
    recursive rotate to swap A1 and A2
B A1 A2  

The other case is where the A block is smaller than the B block.

A B  
first mid last

In this case, we swap until we have used up all of the A elements. The entire A block gets swapped to the middle of the buffer, and an A-sized chunk of the start of the B block (call it B1) goes to the start of the buffer, with the leftover part of B (call it B2) stays at the end of the buffer.

B1 A B2  
 
  first mid last

Again, we can finish with a recursive rotate call, this time to swap A and B2.

B1 A B2  
      recursive rotate to swap A and B2
B1 B2 A  

In both cases, the recursive call is strictly smaller than the original call because we know that both A and B are nonempty: If either was empty, we would have performed a nop early-exit. Therefore, at least one element will be swapped before we reach the recursive call, and we consequently know that the recursion will eventually terminate.

The final case is where the A and B blocks are the same size. In that case, we have swapped all the B elements to the first half and all the A elements to the second half.

B A  
 
  first mid
last

If we are lucky to get here, then we are done!

Note that we don’t need a special case handler for the equal-sized blocks case. We can treat as either the first or second case and let the early-out in the recursive call realize that there is nothing to do.

The number of swaps is n. You can calculate this recursively, since we perform k swaps to move the smaller block, and the recursive call (by induction) performs nk swaps, for a total of n. You can also calculate this directly by observing that at each step, one element gets swapped into its final position (namely, at *first, just before we increment it).

Even though this algorithm and the bidirectional-iterator version both perform n swaps, the bidirectional-iterator version has better locality of reference, so it is preferred if available.

Next time, we’ll apply this to our original problem.

Bonus chatter: You don’t need to do a preliminary std::distance to figure out whether block A or block B is smaller. You can just start swapping elements, and make a note of which happens first: Does first reach the original mid (which means that the A block is smaller) or does mid reach last (which means that the B block is smaller). This “figure it out as you go” doesn’t change the complexity, but it does lower the constant a little bit because you don’t have to iterate through all of the larger block just to realize that it’s took big.

The post How can you swap two adjacent blocks of memory using only forward iterators? appeared first on The Old New Thing.

Read the whole story
alvinashcraft
43 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Create Clutter-Free Layouts with Row and Column Spanning in Blazor DataGrid

1 Share

Create Clutter-Free Layouts with Row and Column Spanning in Blazor DataGrid

TL;DR: Struggling with cluttered grids? Row and column spanning in Blazor DataGrid solves this by merging cells intelligently. Learn how to enable AutoSpan, handle merge/unmerge operations, and apply best practices for performance and usability.

Modern web apps demand clean, readable tables. When the same value repeats across rows or columns, grids can look cluttered and hard to scan. Syncfusion’s Blazor DataGrid solves this with row and column spanning, automatically merging duplicate values into a single cell. The result? A cleaner, more user-friendly table, without extra coding.

This feature has been introduced as part of the Syncfusion® 2025 Volume 4 release, which brings exciting updates across the suite.

In this guide, you’ll learn:

  • What row and column spanning are?
  • How to enable and customize them?
  • How to control spanning programmatically?
  • Key limitations and best practices.

Don’t worry if you’re new to this; everything is explained in a simple, easy-to-understand way.

What are row and column spanning?

Row and Column spanning is enabled by using the AutoSpan property on your SfGrid tag. When adjacent cells share the same value, the grid merges them into a single cell.

The table below lists the available AutoSpanMode options:

Settings Description
AutoSpanMode.None No merging(default).
AutoSpanMode.Row Merges matching cells horizontally in the same row.
AutoSpanMode.Column Merges matching cells vertically in the same column.
AutoSpanMode.HorizontalAndVertical Combines both row and column spans (rows first, then columns).

Here are some example use cases:

  • Row spanning: A TV guide where one show runs across multiple time slots.
  • Column spanning: A work schedule where “Meeting” repeats down consecutive hours.

How to enable row spanning

Row spanning merges identical values across multiple columns in the same row. For example, if Evening News appears twice in a row, the grid combines them into one wider cell.

Here’s how you can do it in code:

@using Syncfusion.Blazor.Grids

<SfGrid DataSource="@TeleCastDataList"
        GridLines="GridLine.Both"
        AutoSpan="AutoSpanMode.Row"
        AllowSelection="false"
        EnableHover="false">
    <GridColumns>
        <GridColumn Field=@nameof(TelecastData.Channel) HeaderText="Channel" Width="200" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(TelecastData.Genre) HeaderText="Genre" Width="120" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(TelecastData.Program12AM) HeaderText="12:00 AM" Width="150"></GridColumn>
        <!-- ... other time slot columns ... -->
    </GridColumns>
</SfGrid>

Note: Try it out with the row spanning demo and refer to the documentation for more insights.

Watch how the feature works in action:

Row spanning in Blazor DataGrid
Row spanning in Blazor DataGrid

How to enable column spanning

Column spanning merges identical values vertically across consecutive rows. For example, lunch might cover multiple hourly slots for one employee.

Code snippet to achieve this:

@using Syncfusion.Blazor.Grids

<SfGrid DataSource="@EmployeeTimeSheet"
        AutoSpan="AutoSpanMode.Column">
    <GridColumns>
        <!-- ... column definitions ... -->
    </GridColumns>
</SfGrid>

Matching entries in a column are displayed in a taller cell, allowing you to see the pattern, as shown below.

Column spanning in Blazor DataGrid
Column spanning in Blazor DataGrid

Note: Try it out with the column spanning demo and refer to the documentation for more information.

Skipping spanning for specific columns

Need spanning everywhere except one column? For example, if you don’t want prime-time TV slots to merge, set the AutoSpan property to AutoSpanMode.None in that column to override the grid settings.

<GridColumn Field=@nameof(TelecastData.Program8PM)
            HeaderText="8:00 PM"
            AutoSpan="AutoSpanMode.None">
</GridColumn>

Note: For more insights, refer to the documentation on disabling row and column spanning.

Merging cells programmatically

Auto spanning is great, but sometimes you need manual control. Syncfusion provides the following methods for custom merging:

Here’s a basic code example with buttons to merge and unmerge single or multiple cells:

@using Syncfusion.Blazor.Grids

<SfButton OnClick="MergeCellsAsync">Merge Cell</SfButton>
<SfButton OnClick="UnMergeCell">UnMerge Cell</SfButton>

<SfButton OnClick="MergeMultipleCellsAsync">Merge Multiple Cells</SfButton>
<SfButton OnClick="UnMergeCells">UnMerge Multiple Cells</SfButton>

<SfButton OnClick="UnMergeAllCells">UnMerge All Cells</SfButton>

<SfGrid @ref="Grid" DataSource="@EmployeeTimeSheet" GridLines="GridLine.Both" AllowSelection="false" EnableHover="false">
    <GridColumns>
        <GridColumn Field=@nameof(EmployeeDetails.EmployeeID) HeaderText="Employee ID" Width="150" TextAlign="TextAlign.Right" IsPrimaryKey="true" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.EmployeeName) HeaderText="Employee Name" Width="180" IsFrozen="true"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_9_00) HeaderText="9:00 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_9_30) HeaderText="9:30 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_10_00) HeaderText="10:00 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_10_30) HeaderText="10:30 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_11_00) HeaderText="11:00 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_11_30) HeaderText="11:30 AM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_12_00) HeaderText="12:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_12_30) HeaderText="12:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_1_00) HeaderText="1:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_1_30) HeaderText="1:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_2_00) HeaderText="2:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_2_30) HeaderText="2:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_3_00) HeaderText="3:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_3_30) HeaderText="3:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_4_00) HeaderText="4:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_4_30) HeaderText="4:30 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
        <GridColumn Field=@nameof(EmployeeDetails.Time_5_00) HeaderText="5:00 PM" Width="150" TextAlign="TextAlign.Center"></GridColumn>
    </GridColumns>
</SfGrid>
@code
{
    public List<EmployeeDetails>? EmployeeTimeSheet { get; set; }
    public SfGrid<EmployeeDetails>? Grid;

    protected override void OnInitialized()
    {
        EmployeeTimeSheet = EmployeeDetails.GetAllRecords();
    }

    public async Task MergeCellsAsync()
    {
        await Grid.MergeCellsAsync(new MergeCellInfo
        {
            RowIndex = 1,
            ColumnIndex = 5,
            ColumnSpan = 2,
        });
    }

    public async Task UnMergeCell()
    {
        await Grid.UnmergeCellsAsync(new UnmergeCellInfo
        {
            RowIndex = 1,
            ColumnIndex = 5,
        });
    }

    public async Task MergeMultipleCellsAsync()
    {
        await Grid.MergeCellsAsync(new[]
        {
            new MergeCellInfo { RowIndex = 0, ColumnIndex = 2, ColumnSpan = 2 },
            new MergeCellInfo { RowIndex = 5, ColumnIndex = 3, ColumnSpan = 3 },
            new MergeCellInfo { RowIndex = 7, ColumnIndex = 4, ColumnSpan = 2 }
        });
    }

    public async Task UnMergeCells()
    {
        await Grid.UnmergeCellsAsync(new[]
        {
            new UnmergeCellInfo { RowIndex = 0, ColumnIndex = 2 },
            new UnmergeCellInfo { RowIndex = 5, ColumnIndex = 3 },
            new UnmergeCellInfo { RowIndex = 7, ColumnIndex = 4 }
        });
    }

    public async Task UnMergeAllCells()
    {
        await Grid.UnmergeAllAsync();
    }
}

Tips and limitations

Before you implement row and column spanning, it’s important to understand a few constraints and best practices to ensure smooth functionality:

This feature has limitations with:

  • AutoFill (that drag-to-fill feature).
  • Grouping (can’t merge across group headers).
  • Some frozen column setups.
  • Detail templates when doing column spans.

Here are some quick tips to optimize your grid:

  • Use row spanning for timelines or event schedules.
  • Use column spanning for tasks or shifts.
  • Combine with frozen columns for better context.
  • Test with large datasets for performance.

Syncfusion Blazor components can be transformed into stunning and efficient web apps.

Conclusion

Thank you for reading! Row and column spanning in Syncfusion Blazor DataGrid, introduced in the Essential Studio® 2025 Volume 4 release, helps you create cleaner, more readable tables with just a few lines of code. It’s perfect for schedules, lists, or any data with repeats. Try it out in the demos.

Check out our Release Notes and What’s New pages to see the other updates in this release, and leave your feedback in the comments section below. We would love to hear from you.

If you’re a Syncfusion user, you can download the setup from the license and downloads page. Otherwise, you can download a free 30-day trial.

You can also contact us through our support forumsupport portal, or feedback portal for queries. We are always happy to assist you!

Read the whole story
alvinashcraft
43 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories