如何让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
相关产品推荐
相关产品推荐

