You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Razor页面中不重定向调用C#函数,实现树形结构子项的异步加载与视图更新

Hey there! Let's sort out this treeview lazy loading problem without those annoying page redirects. Here's a practical, step-by-step solution tailored to your ASP.NET Core Razor Pages setup:

1. Rewrite Your Backend Handler (cshtml.cs)

Instead of using RedirectToPage, we'll create a handler that returns JSON data directly—this lets us fetch child items asynchronously without reloading the whole page.

// Inject your EF Core DbContext via constructor first
private readonly YourDbContext _dbContext;

public YourPageModel(YourDbContext dbContext)
{
    _dbContext = dbContext;
}

// This handler will return child items for a given parent ID
public IActionResult OnPostLoadChildItems(int parentId)
{
    // Use EF Core to query child items based on the parent ID
    var childItems = _dbContext.YourEntity
        .Where(item => item.ParentId == parentId)
        .Select(item => new 
        {
            Id = item.Id,
            Name = item.Name,
            // Add a flag to check if this item has its own children
            HasChildren = _dbContext.YourEntity.Any(child => child.ParentId == item.Id)
        })
        .ToList();

    // Optional: Add permission checks here if needed
    // if (!Model.authority) return Forbid();

    return new JsonResult(childItems);
}

2. Update Your Frontend (cshtml)

We'll add click events to the ▶ buttons, use AJAX to fetch data, and dynamically update the DOM without page refreshes. Keep your existing permission check intact!

HTML for Treeview

@if (Model.authority)
{
    <ul class="treeview">
        @foreach (var mainItem in Model.MainItems)
        {
            <li>
                <button class="expand-btn" data-parent-id="@mainItem.Id">▶</button>
                <span>@mainItem.Name</span>
                <!-- Container to load child items into -->
                <div id="child-container-@mainItem.Id" class="child-items"></div>
            </li>
        }
    </ul>
}

JavaScript for Async Loading

Add this at the bottom of your cshtml file (or link a separate JS file):

// Bind click events to all expand buttons
document.querySelectorAll('.expand-btn').forEach(btn => {
    btn.addEventListener('click', async function() {
        const parentId = this.getAttribute('data-parent-id');
        const childContainer = document.getElementById(`child-container-${parentId}`);

        // Toggle visibility if items are already loaded
        if (childContainer.classList.contains('loaded')) {
            childContainer.style.display = childContainer.style.display === 'none' ? 'block' : 'none';
            this.textContent = childContainer.style.display === 'block' ? '▼' : '▶';
            return;
        }

        try {
            // Send POST request to our backend handler
            const response = await fetch(window.location.pathname + '?handler=LoadChildItems', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    // Include anti-forgery token required by Razor Pages
                    'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
                },
                body: JSON.stringify({ parentId: parentId })
            });

            if (!response.ok) throw new Error('Failed to load child items');
            
            const childItems = await response.json();

            // Render child items dynamically
            let childHtml = '<ul>';
            childItems.forEach(item => {
                const expandIcon = item.HasChildren ? '<button class="expand-btn" data-parent-id="' + item.Id + '">▶</button>' : '';
                childHtml += `
                    <li>
                        ${expandIcon}
                        <span>${item.Name}</span>
                        ${item.HasChildren ? `<div id="child-container-${item.Id}" class="child-items"></div>` : ''}
                    </li>
                `;
            });
            childHtml += '</ul>';

            childContainer.innerHTML = childHtml;
            childContainer.classList.add('loaded');
            this.textContent = '▼'; // Switch to collapse icon

            // Bind click events to newly created expand buttons
            document.querySelectorAll(`#child-container-${parentId} .expand-btn`).forEach(newBtn => {
                newBtn.addEventListener('click', this.onclick);
            });
        } catch (err) {
            console.error(err);
            alert('Failed to load child items. Please try again.');
        }
    });
});

Optional CSS for Better UI

Add this to your stylesheet to make the treeview look cleaner:

.child-items {
    margin-left: 20px;
    display: none;
}
.child-items.loaded {
    display: block;
}
.expand-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
}

Why Your Previous Approaches Didn't Work

  • Server-side function calls in cshtml: Once the page renders, server-side code can't update the DOM directly—you need client-side JS to handle dynamic changes.
  • RedirectToPage: This forces a full page reload, which ruins the smooth treeview experience we want.

内容的提问来源于stack exchange,提问作者로다현

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 06:42:27