首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

DevExpress ASPxPageControl 動態添加 TabPage 含 iframe 完整解決方案

     編輯:程式設計綜合問答

問題現象

後台動態創建 TabPage 並添加 HtmlGenericControl("iframe"),前端渲染出 Tab 標籤但 iframe 內容為空白,不顯示目標頁面。

根本原因

DevExpress 控件樹生命週期:動態添加的控件必須在 Page_Init 或 Page_Load (ViewState 載入前) 建立,且需正確加入 Controls 集合。單純加入 ContentCollection 不會自動處理子控件的渲染生命週期。

正確實現模式

1. 在 Page_Init 中構建 (推薦)

protected void Page_Init(object sender, EventArgs e) {
    if (!IsPostBack) {
        BuildTabsFromDatabase();
    } else {
        // Postback 時必須重建,否則 ViewState 找不到控件
        BuildTabsFromDatabase();
    }
}

private void BuildTabsFromDatabase() {
    DataTable dt = GetTabData(); // 從資料庫讀取
    
    foreach (DataRow row in dt.Rows) {
        string cellId = row["CellID"].ToString();
        string cellUrl = row["CellURL"].ToString();
        string cellName = row["CellName"].ToString();
        
        // 1. 創建 TabPage
        TabPage tabPage = new TabPage(cellName, cellId);
        
        // 2. 創建內容容器 (關鍵:使用 TemplateContainer 或直接加 Controls)
        var contentPanel = new Panel { ID = "pnl_" + cellId };
        
        // 3. 創建 iframe - 使用 LiteralControl 輸出原始 HTML 最可靠
        string iframeHtml = $@"
            <iframe id='ifr_{cellId}' 
                    src='{ResolveUrl(cellUrl)}' 
                    frameborder='0' 
                    style='width:100%;height:100%;border:none;'>
            </iframe>";
        contentPanel.Controls.Add(new LiteralControl(iframeHtml));
        
        // 4. 將 Panel 加入 TabPage 的 Controls (而非 ContentCollection)
        tabPage.Controls.Add(contentPanel);
        
        // 5. 添加到 PageControl
        pageControl.TabPages.Add(tabPage);
    }
}

2. 替代方案:使用 ITemplate 動態模板

public class IframeTemplate : ITemplate {
    private readonly string _url;
    private readonly string _id;
    
    public IframeTemplate(string url, string id) {
        _url = url; _id = id;
    }
    
    public void InstantiateIn(Control container) {
        var literal = new LiteralControl($@"
            <iframe id='{_id}' src='{_url}' frameborder='0' style='width:100%;height:500px;'></iframe>");
        container.Controls.Add(literal);
    }
}

// 使用
var tabPage = new TabPage(cellName, cellId);
tabPage.Templates.Content = new IframeTemplate(cellUrl, "ifr_" + cellId);
pageControl.TabPages.Add(tabPage);

關鍵差異對比

錯誤做法正確做法
用 HtmlGenericControl("iframe")用 LiteralControl 輸出完整 iframe HTML
加入 ContentCollection加入 TabPage.Controls 或用 Templates.Content
只在 !IsPostBack 建立每次 Request 都要重建 (或用 ViewState 自動恢復)
iframe src 用相對路徑用 ResolveUrl() 或絕對路徑

進階:iframe 高度自適應

<script>
function resizeIframe(iframeId) {
    var iframe = document.getElementById(iframeId);
    iframe.onload = function() {
        try {
            iframe.style.height = iframe.contentWindow.document.body.scrollHeight + 'px';
        } catch (e) {
            // 跨域無法獲取高度,需目標頁面配合 postMessage
        }
    };
}
// 頁面載入後調用
resizeIframe('ifr_123');
</script>

跨域 iframe 通訊 (postMessage)

// 父頁面
window.addEventListener('message', function(e) {
    if (e.data.type === 'resize') {
        document.getElementById(e.data.iframeId).style.height = e.data.height + 'px';
    }
});

// 子頁面 (iframe 內)
window.parent.postMessage({
    type: 'resize',
    iframeId: 'ifr_123',
    height: document.body.scrollHeight
}, '*');

總結檢查清單

  • ☑ 在 Page_Init 中動態創建 TabPage
  • ☑ Postback 時同樣重建 (或啟用 ViewState 讓框架自動恢復)
  • ☑ iframe 用 LiteralControl 輸出 HTML,而非伺服器控件
  • ☑ ResolveUrl() 處理虛擬路徑
  • ☑ 設定 iframe style='width:100%;height:100%' 撐滿 Tab 內容區
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved