首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET Calendar 控制項實作類 Yupoo 日曆相簿效果:日期標記圖片、點擊彈出詳情

     編輯:關於ASP.NET

Yupoo (現已轉型) 早期的「日曆相簿」以直觀的月曆介面展示每日照片,點擊日期即看當日相簿。本文示範如何使用 ASP.NET `Calendar` 伺服器控制項,搭配 `DayRender` 事件動態標記有照片的日期、`SelectionChanged` 事件處理點擊彈出詳情,達成高度客製化的日曆相簿體驗。

核心技術點

  • `Calendar.DayRender`:每個日期單元格渲染前觸發,可注入 Image、CSS Class、Tooltip
  • `Calendar.SelectionChanged`:使用者點擊日期觸發,取得 `SelectedDate` 顯示詳情
  • `Calendar.VisibleDate`:控制目前顯示的月份
  • 樣式屬性:`DayStyle`、`TodayDayStyle`、`SelectedDayStyle`、`OtherMonthDayStyle` 等精細控制外觀

ASPX 頁面標記

<asp:Calendar ID="Calendar1" runat="server" 
    OnDayRender="Calendar1_DayRender"
    OnSelectionChanged="Calendar1_SelectionChanged"
    OnVisibleMonthChanged="Calendar1_VisibleMonthChanged"
    ShowGridLines="True"
    NextPrevFormat="FullMonth"
    TitleFormat="MonthYear"
    FirstDayOfWeek="Sunday">
    <DayStyle CssClass="cal-day" />
    <TodayDayStyle CssClass="cal-today" BackColor="#FFFFCC" />
    <SelectedDayStyle CssClass="cal-selected" BackColor="#FF6600" ForeColor="White" />
    <OtherMonthDayStyle CssClass="cal-other-month" ForeColor="#CCCCCC" />
    <SelectorStyle CssClass="cal-selector" />
    <WeekendDayStyle CssClass="cal-weekend" />
</asp:Calendar>

<!-- 詳情顯示區 (初始隱藏) -->
<asp:Panel ID="pnlDetail" runat="server" Visible="false" CssClass="detail-panel">
    <asp:Image ID="imgPhoto" runat="server" />
    <asp:Label ID="lblDate" runat="server" CssClass="detail-date" />
    <asp:Label ID="lblDescription" runat="server" CssClass="detail-desc" />
    <asp:Button ID="btnClose" Text="關閉" OnClick="btnClose_Click" runat="server" />
</asp:Panel>

後台程式碼 (C#)

public partial class CalendarAlbum : System.Web.UI.Page
{
    // 模擬資料來源:日期 -> 相片資訊
    private Dictionary _photos = new Dictionary();

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            LoadSampleData();
            Calendar1.VisibleDate = DateTime.Today;
        }
    }

    private void LoadSampleData()
    {
        // 實務從資料庫載入:SELECT PhotoDate, ImageUrl, Title, Description FROM Photos
        _photos[new DateTime(2024, 1, 5)] = new PhotoInfo 
        { ImageUrl = "~/Photos/20240105.jpg", Title = "新年首登", Description = "陽明山日出" };
        _photos[new DateTime(2024, 1, 12)] = new PhotoInfo 
        { ImageUrl = "~/Photos/20240112.jpg", Title = "週末騎行", Description = "河濱自行車道" };
        _photos[new DateTime(2024, 1, 28)] = new PhotoInfo 
        { ImageUrl = "~/Photos/20240128.jpg", Title = "年夜飯", Description = "全家福" };
    }

    // 關鍵:動態標記有照片的日期
    protected void Calendar1_DayRender(object sender, DayRenderEventArgs e)
    {
        if (_photos.ContainsKey(e.Day.Date))
        {
            var photo = _photos[e.Day.Date];
            // 加入圖片縮圖
            var img = new Image 
            { 
                ImageUrl = photo.ImageUrl, 
                Width = Unit.Pixel(40), 
                Height = Unit.Pixel(30),
                ToolTip = photo.Title,
                CssClass = "photo-thumb"
            };
            e.Cell.Controls.Add(img);
            // 標記 CSS 類別供樣式區分
            e.Cell.CssClass += " has-photo";
        }
    }

    // 使用者點擊日期
    protected void Calendar1_SelectionChanged(object sender, EventArgs e)
    {
        DateTime selected = Calendar1.SelectedDate;
        if (_photos.ContainsKey(selected))
        {
            var photo = _photos[selected];
            imgPhoto.ImageUrl = photo.ImageUrl;
            lblDate.Text = selected.ToString("yyyy年MM月dd日");
            lblDescription.Text = $"{photo.Title}:{photo.Description}";
            pnlDetail.Visible = true;
        }
        else
        {
            pnlDetail.Visible = false; // 無照片不顯示詳情
        }
    }

    // 切換月份時重新載入該月資料 (大量資料時必要)
    protected void Calendar1_VisibleMonthChanged(object sender, MonthChangedEventArgs e)
    {
        // 實務:LoadPhotosForMonth(e.NewDate.Year, e.NewDate.Month);
    }

    protected void btnClose_Click(object sender, EventArgs e)
    {
        pnlDetail.Visible = false;
        Calendar1.SelectedDates.Clear(); // 取消選中狀態
    }
}

public class PhotoInfo
{
    public string ImageUrl { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
}

CSS 樣式關鍵 (內嵌或外部檔案)

.cal-day { height: 60px; width: 60px; vertical-align: top; padding: 2px; }
.cal-day.has-photo { background-color: #E8F5E9; border: 2px solid #4CAF50; }
.photo-thumb { display: block; margin: 2px auto; border-radius: 4px; }
.cal-today { background-color: #FFF3E0 !important; border: 2px solid #FF9800; }
.cal-selected { background-color: #FF6600 !important; }
.cal-other-month { background-color: #F5F5F5; }
.detail-panel { 
    position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
    background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.2);
    z-index: 1000; max-width: 400px; text-align: center;
}
.detail-panel img { max-width: 100%; height: auto; margin-bottom: 10px; }

效能與擴充考量

挑戰解決策略
大量照片 (萬筆) 載入緩慢`VisibleMonthChanged` 只載入當月資料;使用 `OutputCache` 快取月份資料
行動裝置觸控體驗加大日期單元格、支援滑動切換月份 (jQuery Mobile / Hammer.js)
多張照片同一天縮圖改用 Carousel、或顯示數量徽章 `e.Cell.Controls.Add(new Label { Text = $"+{count}" })`
無障礙存取加入 `aria-label`、鍵盤導航支援、高對比度模式

現代化替代方案

  • FullCalendar.js (jQuery/React/Vue) - 功能最豐富的客戶端日曆
  • Blazor Calendar Component - C# 寫前端、WebAssembly/WASM
  • CSS Grid + JS** 自製日曆 - 完全控制、零依賴、效能最佳
  • Telerik / DevExpress / Syncfusion** - 企業級元件庫、內建匯出/列印/拖曳

`Calendar` 控制項雖屬 WebForms 經典元件,但其 `DayRender` 事件模式——**資料驅動 UI 渲染**——是現代前端框架 (Vue `v-for`、React `map`、Blazor `@foreach`) 共同的核心範式。掌握這個控制項的客製化技巧,不僅能維護舊系統,更能深化對「宣告式 UI 渲染」的本質理解。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved