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

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

  1. 声明转换器资源并设置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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:25:19