WPF Calendar点击搜索按钮后选中日期被取消,需保留选中状态求助
解决WPF Calendar选中日期范围丢失的问题
我之前在做WPF项目时也遇到过一模一样的问题——用SingleRange模式的Calendar,点击搜索按钮或者控件失去焦点时,选中的日期范围就没了,太头疼了!下面给你几个实用的解决办法,亲测有效:
方法1:手动保存选中范围到变量(代码后台快速解决)
这是最直接的方案,不需要改样式或者写复杂逻辑,只需要把用户选中的日期范围存在变量里,搜索时用变量而不是直接取Calendar的SelectedDates。
- 在窗口/UserControl的代码后台定义两个可空DateTime变量:
private DateTime? _selectedStartDate; private DateTime? _selectedEndDate; - 给Calendar订阅
SelectedDatesChanged事件,实时保存选中的范围:private void DatesCalendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e) { var calendar = sender as Calendar; if (calendar?.SelectedDates != null && calendar.SelectedDates.Count > 0) { _selectedStartDate = calendar.SelectedDates.First(); _selectedEndDate = calendar.SelectedDates.Last(); } } - 在搜索按钮的点击事件里,用这两个变量去查询数据库:
private void SearchButton_Click(object sender, RoutedEventArgs e) { if (_selectedStartDate.HasValue && _selectedEndDate.HasValue) { // 这里写你的数据库查询逻辑,使用_selectedStartDate和_selectedEndDate // 比如:var results = _dbContext.Entries.Where(x => x.Date >= _selectedStartDate && x.Date <= _selectedEndDate); } }
这样就算Calendar的选中状态被清除了,我们已经把用户的选择保存下来了,完全不影响查询。
方法2:用附加属性阻止选中范围丢失(通用复用方案)
如果你的项目里多个地方都用了Calendar,不想每个都写重复代码,可以写一个附加属性来控制选中状态的保留,让Calendar失去焦点时自动恢复之前的选中范围。
- 创建一个静态辅助类:
public static class CalendarSelectionHelper { public static readonly DependencyProperty KeepSelectedRangeProperty = DependencyProperty.RegisterAttached( "KeepSelectedRange", typeof(bool), typeof(CalendarSelectionHelper), new PropertyMetadata(false, OnKeepSelectedRangeChanged)); public static bool GetKeepSelectedRange(DependencyObject obj) { return (bool)obj.GetValue(KeepSelectedRangeProperty); } public static void SetKeepSelectedRange(DependencyObject obj, bool value) { obj.SetValue(KeepSelectedRangeProperty, value); } private static void OnKeepSelectedRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var calendar = d as Calendar; if (calendar == null) return; if ((bool)e.NewValue) { calendar.LostFocus += OnCalendarLostFocus; calendar.SelectedDatesChanged += OnCalendarSelectedDatesChanged; } else { calendar.LostFocus -= OnCalendarLostFocus; calendar.SelectedDatesChanged -= OnCalendarSelectedDatesChanged; } } private static void OnCalendarSelectedDatesChanged(object sender, SelectionChangedEventArgs e) { var calendar = sender as Calendar; if (calendar?.SelectedDates != null) { // 保存当前选中的日期列表 SetSavedSelectedDates(calendar, new List<DateTime>(calendar.SelectedDates)); } } private static void OnCalendarLostFocus(object sender, RoutedEventArgs e) { var calendar = sender as Calendar; var savedDates = GetSavedSelectedDates(calendar); if (savedDates != null && savedDates.Count > 0) { // 恢复之前选中的日期范围 calendar.SelectedDates.Clear(); foreach (var date in savedDates) { calendar.SelectedDates.Add(date); } } } // 用于存储选中日期的附加属性 private static readonly DependencyProperty SavedSelectedDatesProperty = DependencyProperty.RegisterAttached( "SavedSelectedDates", typeof(List<DateTime>), typeof(CalendarSelectionHelper), new PropertyMetadata(null)); private static List<DateTime> GetSavedSelectedDates(DependencyObject obj) { return (List<DateTime>)obj.GetValue(SavedSelectedDatesProperty); } private static void SetSavedSelectedDates(DependencyObject obj, List<DateTime> value) { obj.SetValue(SavedSelectedDatesProperty, value); } } - 在XAML里给Calendar添加这个附加属性:
<Calendar x:Name="DatesCalendar" SelectionMode="SingleRange" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" Margin="0,10" VerticalAlignment="Center" local:CalendarSelectionHelper.KeepSelectedRange="True" />
(注意把local换成你的辅助类所在的命名空间)
这样Calendar失去焦点或者点击其他控件时,都会自动恢复之前的选中范围,用户体验更流畅。
方法3:MVVM模式下绑定SelectedDates(优雅推荐)
如果你的项目用了MVVM框架,直接把Calendar的SelectedDates绑定到ViewModel的集合是最优雅的方案,因为数据和UI分离,不用担心UI状态丢失。
- 在ViewModel里定义一个ObservableCollection
属性: private ObservableCollection<DateTime> _selectedDateRange = new ObservableCollection<DateTime>(); public ObservableCollection<DateTime> SelectedDateRange { get => _selectedDateRange; set { _selectedDateRange = value; OnPropertyChanged(); // 这里需要实现INotifyPropertyChanged接口 } } - 在XAML里绑定这个属性:
<Calendar x:Name="DatesCalendar" SelectionMode="SingleRange" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" Margin="0,10" VerticalAlignment="Center" SelectedDates="{Binding SelectedDateRange, Mode=TwoWay}" /> - 搜索时直接用ViewModel里的
SelectedDateRange:// ViewModel里的搜索命令 public ICommand SearchCommand => new RelayCommand(() => { if (SelectedDateRange.Count > 0) { var startDate = SelectedDateRange.First(); var endDate = SelectedDateRange.Last(); // 执行数据库查询逻辑 } });
双向绑定会实时同步用户的选择到ViewModel,不管UI怎么变化,ViewModel里的集合始终保留着用户最后选择的范围,完全不用担心丢失问题。
内容的提问来源于stack exchange,提问作者user5500750
相关产品推荐
相关产品推荐

