it

C# Blazor กับ Low Code No Code — วิธีใช้ Blazor

C# Blazor กับ Low Code No Code — วิธีใช้ Blazor

Blazor Web Framework

C# Blazor กับ Low Code No Code — วิธีใช้ Blazor

Blazor เป็น Web Framework จาก Microsoft ที่ให้เขียน Web App ด้วย C# แทน JavaScript มี Component-based Architecture เหมือน React/Vue แต่ใช้ C# และ Razor Syntax รองรับทั้ง Server-side และ Client-side (WebAssembly)

Low Code/No Code เป็นแนวคิดที่ให้สร้าง Application ด้วยการลาก Drop Components เขียน Code น้อยที่สุดหรือไม่ต้องเขียนเลย Blazor สามารถสร้าง Low Code Platform ได้ด้วย Dynamic Components และ Drag-and-Drop

Blazor Application Development

// === Blazor Web App ===

// dotnet new blazor -n MyBlazorApp --interactivity Auto

// cd MyBlazorApp



// === Components/UserList.razor ===

@page "/users"

@using MyBlazorApp.Models

@using MyBlazorApp.Services

@inject IUserService UserService

@inject NavigationManager Navigation



<PageTitle>Users</PageTitle>



<h3>User Management</h3>



@if (_loading)

{

    <div class="spinner-border" role="status">

        <span class="visually-hidden">Loading...</span>

    </div>

}

else

{

    <div class="mb-3">

        <input type="text" class="form-control"

               placeholder="Search users..."

               @bind-value="_searchText"

               @bind-value:event="oninput"

               @onkeyup="OnSearch" />

    </div>



    <table class="table table-striped">

        <thead>

            <tr>

                <th @onclick='() => SortBy("Name")'>Name</th>

                <th @onclick='() => SortBy("Email")'>Email</th>

                <th>Role</th>

                <th>Actions</th>

            </tr>

        </thead>

        <tbody>

            @foreach (var user in _filteredUsers)

            {

                <tr>

                    <td>@user.Name</td>

                    <td>@user.Email</td>

                    <td><span class="badge bg-primary">@user.Role</span></td>

                    <td>

                        <button class="btn btn-sm btn-outline-primary"

                                @onclick="() => EditUser(user.Id)">Edit</button>

                        <button class="btn btn-sm btn-outline-danger"

                                @onclick="() => DeleteUser(user.Id)">Delete</button>

                    </td>

                </tr>

            }

        </tbody>

    </table>



    <p>Total: @_filteredUsers.Count users</p>

}



@code {

    private List<User> _users = new();

    private List<User> _filteredUsers = new();

    private string _searchText = "";

    private bool _loading = true;

    private string _sortField = "Name";

    private bool _sortAsc = true;



    protected override async Task OnInitializedAsync()

    {

        _users = await UserService.GetUsersAsync();

        _filteredUsers = _users;

        _loading = false;

    }



    private void OnSearch()

    {

        _filteredUsers = string.IsNullOrEmpty(_searchText)

            ? _users

            : _users.Where(u =>

                u.Name.Contains(_searchText, StringComparison.OrdinalIgnoreCase) ||

                u.Email.Contains(_searchText, StringComparison.OrdinalIgnoreCase))

              .ToList();

    }



    private void SortBy(string field)

    {

        if (_sortField == field) _sortAsc = !_sortAsc;

        else { _sortField = field; _sortAsc = true; }



        _filteredUsers = _sortField switch

        {

            "Name" => _sortAsc

                ? _filteredUsers.OrderBy(u => u.Name).ToList()

                : _filteredUsers.OrderByDescending(u => u.Name).ToList(),

            "Email" => _sortAsc

                ? _filteredUsers.OrderBy(u => u.Email).ToList()

                : _filteredUsers.OrderByDescending(u => u.Email).ToList(),

            _ => _filteredUsers,

        };

    }



    private void EditUser(int id) => Navigation.NavigateTo($"/users/edit/{id}");



    private async Task DeleteUser(int id)

    {

        await UserService.DeleteUserAsync(id);

        _users = await UserService.GetUsersAsync();

        OnSearch();

    }

}

Low Code Component Builder

=== Low Code Dynamic Form Builder ===

Components/FormBuilder.razor

DynamicField.cs — Field Definition

namespace MyBlazorApp.LowCode;

public class DynamicField

{

public string Name { get; set; } = "";

public string Label { get; set; } = "";

public string Type { get; set; } = "text"; // text, number, email, select, checkbox, textarea

public bool Required { get; set; }

public string Placeholder { get; set; } = "";

public List&lt;string&gt; Options { get; set; } = new(); // สำหรับ Select

public string DefaultValue { get; set; } = "";

public int? MinLength { get; set; }

public int? MaxLength { get; set; }

public string ValidationMessage { get; set; } = "";

}

public class FormDefinition

{

public string Title { get; set; } = "";

public string Description { get; set; } = "";

public List&lt;DynamicField&gt; Fields { get; set; } = new();

public string SubmitUrl { get; set; } = "";

public string SubmitMethod { get; set; } = "POST";

}

FormRenderer.razor — Render Dynamic Form

@using MyBlazorApp.LowCode

&lt;EditForm Model="_formData" OnValidSubmit="OnSubmit"&gt;

&lt;h4&gt;@Definition.Title&lt;/h4&gt;

&lt;p&gt;@Definition.Description&lt;/p&gt;

@foreach (var field in Definition.Fields)

{

&lt;div class="mb-3"&gt;

&lt;label class="form-label"&gt;@field.Label&lt;/label&gt;

เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: Apache Arrow Micro-segmentation

@switch (field.Type)

{

case "text":

case "email":

case "number":

C# Blazor กับ Low Code No Code — วิธีใช้ Blazor

&lt;input type="@field.Type"

class="form-control"

placeholder="@field.Placeholder"

@bind="_formData[field.Name]"

required="@field.Required" /&gt;

break;

case "textarea":

&lt;textarea class="form-control"

rows="4"

แนะนำเพิ่มเติม — SiamCafeBook

@bind="_formData[field.Name]"&gt;&lt;/textarea&gt;

break;

case "select":

&lt;select class="form-select" @bind="_formData[field.Name]"&gt;

&lt;option value=""&gt;-- Select --&lt;/option&gt;

@foreach (var opt in field.Options)

{

&lt;option value="@opt"&gt;@opt&lt;/option&gt;

}

&lt;/select&gt;

break;

case "checkbox":

&lt;input type="checkbox" class="form-check-input"

@bind="_formData[field.Name]" /&gt;

break;

}

&lt;/div&gt;

}

&lt;button type="submit" class="btn btn-primary"&gt;Submit&lt;/button&gt;

&lt;/EditForm&gt;

ตัวอย่าง Form Definition (JSON)

var contactForm = new FormDefinition

{

Title = "Contact Form",

Description = "กรอกข้อมูลติดต่อ",

SubmitUrl = "/api/contacts",

Fields = new List&lt;DynamicField&gt;

เนื้อหาเกี่ยวข้อง — อ่านต่อ: PostgreSQL Full Text Search Internal Developer

{

new() { Name = "name", Label = "ชื่อ", Type = "text", Required = true },

new() { Name = "email", Label = "Email", Type = "email", Required = true },

new() { Name = "phone", Label = "โทรศัพท์", Type = "text" },

new() { Name = "department", Label = "แผนก", Type = "select",

Options = new() { "Sales", "Support", "Engineering" } },

new() { Name = "message", Label = "ข้อความ", Type = "textarea", Required = true },

new() { Name = "subscribe", Label = "รับข่าวสาร", Type = "checkbox" },

},

};

Console.WriteLine($"Form: {contactForm.Title}");

Console.WriteLine($"Fields: {contactForm.Fields.Count}");

foreach (var f in contactForm.Fields)

Console.WriteLine($" {f.Name} ({f.Type}) {(f.Required ? "*" : "")}");

Blazor Component Library

=== Reusable Blazor Components ===

Components/Shared/DataTable.razor

DataTable&lt;T&gt; — Generic Data Table Component

@typeparam T

&lt;div class="table-responsive"&gt;

แนะนำเพิ่มเติม — เรียนเทรดกับ iCafeForex

@if (ShowSearch)

{

&lt;input type="text" class="form-control mb-3"

placeholder="Search..."

@bind-value="SearchText"

@bind-value:event="oninput" /&gt;

}

&lt;table class="table table-hover"&gt;

&lt;thead&gt;

&lt;tr&gt;

@foreach (var col in Columns)

{

&lt;th style="cursor:pointer"

@onclick="() =&gt; Sort(col.Field)"&gt;

@col.Title

@if (_sortField == col.Field)

เนื้อหาเกี่ยวข้อง — อ่านต่อ: JavaScript Deno Deploy Architecture Design

{

&lt;span&gt;@(_sortAsc ? "▲" : "▼")&lt;/span&gt;

}

&lt;/th&gt;

}

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

@foreach (var item in PagedItems)

{

&lt;tr @onclick="() =&gt; OnRowClick.InvokeAsync(item)"

style="cursor:pointer"&gt;

@RowTemplate(item)

&lt;/tr&gt;

}

&lt;/tbody&gt;

&lt;/table&gt;

&lt;nav&gt;

&lt;ul class="pagination"&gt;

@for (var i = 1; i &lt;= TotalPages; i++)

{

var page = i;

&lt;li class="page-item @(page == CurrentPage ? "active" : "")"&gt;

&lt;a class="page-link" @onclick="() =&gt; GoToPage(page)"&gt;@page&lt;/a&gt;

&lt;/li&gt;

}

&lt;/ul&gt;

&lt;/nav&gt;

&lt;/div&gt;

@code {

[Parameter] public List&lt;T&gt; Items { get; set; } = new();

[Parameter] public List&lt;ColumnDef&gt; Columns { get; set; } = new();

[Parameter] public RenderFragment&lt;T&gt; RowTemplate { get; set; }

[Parameter] public EventCallback&lt;T&gt; OnRowClick { get; set; }

[Parameter] public bool ShowSearch { get; set; } = true;

เนื้อหาเกี่ยวข้อง — อ่านต่อ: Python Pydantic SaaS Architecture

[Parameter] public int PageSize { get; set; } = 10;

private string SearchText = "";

private int CurrentPage = 1;

private string _sortField = "";

private bool _sortAsc = true;

private int TotalPages =&gt; (int)Math.Ceiling(Items.Count / (double)PageSize);

private List&lt;T&gt; PagedItems =&gt; Items

.Skip((CurrentPage - 1) * PageSize)

.Take(PageSize).ToList();

private void GoToPage(int page) =&gt; CurrentPage = page;

private void Sort(string field) { /* sorting logic */ }

}

ColumnDef.cs

public class ColumnDef

{

public string Field { get; set; } = "";

public string Title { get; set; } = "";

public string Width { get; set; } = "";

public bool Sortable { get; set; } = true;

}

ใช้งาน

&lt;DataTable Items="users" Columns="columns" PageSize="20"&gt;

&lt;RowTemplate Context="user"&gt;

&lt;td&gt;@user.Name&lt;/td&gt;

&lt;td&gt;@user.Email&lt;/td&gt;

&lt;td&gt;@user.Role&lt;/td&gt;

&lt;/RowTemplate&gt;

&lt;/DataTable&gt;

Console.WriteLine("Blazor Component Library:");

Console.WriteLine(" DataTable&lt;T&gt; — Generic sortable, searchable, paginated table");

Console.WriteLine(" FormBuilder — Dynamic form from JSON definition");

Console.WriteLine(" DragDrop — Drag and drop UI builder");

Console.WriteLine(" ChartWidget — Chart.js wrapper for Blazor");

Best Practices

  • Component Reusability: สร้าง Generic Components ที่ใช้ซ้ำได้ เช่น DataTable<T>, FormField
  • State Management: ใช้ Cascading Parameters หรือ Fluxor สำหรับ Global State
  • Lazy Loading: ใช้ Lazy Assembly Loading สำหรับ Blazor WASM ลด Initial Load
  • Virtualization: ใช้ Virtualize Component สำหรับ List ที่มีข้อมูลมาก
  • Error Boundaries: ใช้ ErrorBoundary Component จับ Errors ไม่ให้ App Crash
  • Pre-rendering: เปิด Pre-rendering สำหรับ SEO และ Initial Load เร็วขึ้น

Blazor คืออะไร

Web Framework จาก Microsoft เขียน Web App ด้วย C# แทน JavaScript มี Blazor Server ประมวลผลบน Server SignalR และ Blazor WASM รันบน Browser WebAssembly ไม่ต้องเขียน JavaScript

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง