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

如何让WPF DatePicker仅以Decade模式显示并点击年份直接填入文本框?

实现WPF DatePicker仅保留Decade显示模式并点击年份直接填入文本框

当然可行!你当前的代码只是在日历打开时切换到了Decade模式,但没有阻止Calendar默认的模式切换行为(点击年份会自动切到Month模式)。我们只需要通过几个事件处理来覆盖这个默认逻辑,同时实现点击年份后关闭日历并填入年份的需求。

具体实现步骤:

  • 阻止Calendar切换到其他显示模式:订阅Calendar的DisplayModeChanged事件,一旦检测到模式要切换,强制切回Decade模式。
  • 处理年份选择逻辑:订阅Calendar的SelectedDatesChanged事件,当用户点击年份时,提取年份值,更新DatePicker的文本并关闭日历弹窗。
  • 清理事件订阅(避免内存泄漏):在Calendar关闭时取消订阅之前绑定的事件,防止内存泄漏。

修改后的完整代码

XAML部分(增加CalendarClosed事件绑定):

<DatePicker x:Name="Dtp_Date" HorizontalAlignment="Left" Margin="117,221,0,0" 
            VerticalAlignment="Top" 
            CalendarOpened="Dtp_Date_CalendarOpened"
            CalendarClosed="Dtp_Date_CalendarClosed">
    <DatePicker.Resources>
        <Style TargetType="DatePickerTextBox">
            <Setter Property="Text" Value="Choose year..."/>
        </Style>
    </DatePicker.Resources>
</DatePicker>

后台C#代码:

private Calendar _calendar;

private void Dtp_Date_CalendarOpened(object sender, RoutedEventArgs e)
{
    DatePicker datepicker = (DatePicker)sender;
    Popup popup = (Popup)datepicker.Template.FindName("PART_Popup", datepicker);
    
    if (popup?.Child is Calendar cal)
    {
        _calendar = cal;
        // 初始设置为Decade模式
        cal.DisplayMode = CalendarMode.Decade;
        // 订阅模式变更事件,阻止切换到其他模式
        cal.DisplayModeChanged += Calendar_DisplayModeChanged;
        // 订阅日期选择事件,处理年份点击
        cal.SelectedDatesChanged += Calendar_SelectedDatesChanged;
    }
}

private void Calendar_DisplayModeChanged(object sender, CalendarModeChangedEventArgs e)
{
    // 强制切回Decade模式,阻止默认的模式切换
    ((Calendar)sender).DisplayMode = CalendarMode.Decade;
}

private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
    if (_calendar?.SelectedDate.HasValue == true)
    {
        DatePicker datepicker = (DatePicker)Dtp_Date;
        // 获取选中的年份
        int selectedYear = _calendar.SelectedDate.Value.Year;
        // 更新文本框显示为年份
        DatePickerTextBox textBox = (DatePickerTextBox)datepicker.Template.FindName("PART_TextBox", datepicker);
        textBox.Text = selectedYear.ToString();
        
        // 也可以设置SelectedDate为该年份的第一天(可选,根据需求决定)
        // datepicker.SelectedDate = new DateTime(selectedYear, 1, 1);
        
        // 关闭日历弹窗
        datepicker.IsDropDownOpen = false;
    }
}

private void Dtp_Date_CalendarClosed(object sender, RoutedEventArgs e)
{
    // 取消事件订阅,避免内存泄漏
    if (_calendar != null)
    {
        _calendar.DisplayModeChanged -= Calendar_DisplayModeChanged;
        _calendar.SelectedDatesChanged -= Calendar_SelectedDatesChanged;
        _calendar = null;
    }
}

效果说明:

  • 打开DatePicker时,日历会直接以Decade模式显示,不会切换到其他模式。
  • 点击任意年份后,日历弹窗会自动关闭,文本框会显示选中的年份值。
  • 可选设置SelectedDate为该年份的第一天,这样后续如果需要获取DatePicker的日期值也能拿到有效数据(如果不需要可以注释掉这行)。

内容的提问来源于stack exchange,提问作者Lucy82

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:24:56