WPF MVVM:如何将日历控件选中日期绑定至ViewModel?
解决方案
要实现无需代码后置的双向同步,核心是利用双向数据绑定+值转换器,将Calendar的SelectedDates(类型为SelectedDatesCollection)与ViewModel中的ObservableCollection<DateTime>属性互相转换,同时让ListBox绑定到ViewModel的集合实现同步。
步骤1:实现ViewModel
定义包含ObservableCollection<DateTime>属性的ViewModel,并实现INotifyPropertyChanged接口:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; public class MainViewModel : INotifyPropertyChanged { private ObservableCollection<DateTime> _selectedDates; public ObservableCollection<DateTime> SelectedDates { get => _selectedDates; set { _selectedDates = value; OnPropertyChanged(); } } public MainViewModel() { SelectedDates = new ObservableCollection<DateTime>(); } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
步骤2:创建值转换器
因为SelectedDatesCollection和ObservableCollection<DateTime>类型不匹配,需要转换器实现双向转换:
using System; using System.Collections.ObjectModel; using System.Globalization; using System.Windows.Data; using System.Windows.Controls; public class SelectedDatesConverter : IValueConverter { // 将SelectedDatesCollection转为ObservableCollection<DateTime> public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is SelectedDatesCollection calendarDates) { return new ObservableCollection<DateTime>(calendarDates); } return null; } // 将ObservableCollection<DateTime>转回SelectedDatesCollection public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var selectedDates = new SelectedDatesCollection(); if (value is ObservableCollection<DateTime> viewModelDates) { foreach (var date in viewModelDates) { selectedDates.Add(date); } } return selectedDates; } }
步骤3:配置XAML
- 声明转换器资源并设置ViewModel为DataContext:
<Window x:Class="YourNamespace.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourNamespace" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <!-- 声明转换器 --> <local:SelectedDatesConverter x:Key="SelectedDatesConverter"/> </Window.Resources> <!-- 设置ViewModel为DataContext --> <Window.DataContext> <local:MainViewModel/> </Window.DataContext> <StackPanel> <!-- 日历控件双向绑定到ViewModel的SelectedDates --> <Calendar Name="calendarA" SelectionMode="MultipleRange" SelectedDates="{Binding SelectedDates, Mode=TwoWay, Converter={StaticResource SelectedDatesConverter}}"/> <!-- 列表框绑定到ViewModel的SelectedDates,自动同步显示 --> <ListBox x:Name="dateListBox" ItemsSource="{Binding SelectedDates}" SelectionMode="Extended" Margin="10 0"/> </StackPanel> </Window>
说明
- 当你在
Calendar中选择/取消日期时,转换器会将SelectedDatesCollection转为ObservableCollection<DateTime>同步到ViewModel;反之,ViewModel中SelectedDates的变化也会通过转换器转回SelectedDatesCollection,同步到Calendar。 ListBox直接绑定ViewModel的SelectedDates,会自动显示最新的选中日期集合;如果需要让ListBox的选中项也同步到ViewModel,可以额外给ListBox的SelectedItems添加绑定(不过SelectedItems默认不支持双向绑定,这时候可以用附加属性或转换器处理,当前方案已满足核心的选中日期集合同步需求)。
内容的提问来源于stack exchange,提问作者IRP_HANDLER
相关产品推荐
相关产品推荐

