基于月份的WPF日历自定义(月份为列,#Day为行)

时间:2015-11-15 08:48:32

标签: wpf calendar

无法找到一种方法来自定义WPF日历控件以在一列中显示一个月的日期。任何想法如何以优雅的方式实现这一目标?   ╔════════╦═════╦═════╦═════╦════╗ ║ ║ Jan ║ Feb ║ Mar ║ .. ║ ╠════════╬═════╬═════╬═════╬════╣ ║ #1 ║ ║ ║ ║ ║ ║ #2 ║ ║ ║ ║ ║ ║ #3 ║ ║ ║ ║ ║ ║ .. ║ ║ ║ ║ ║ ║ #30 ║ ║ ║ ║ ║ ╚════════╩═════╩═════╩═════╩════╝

1 个答案:

答案 0 :(得分:1)

据我所知,您需要一个可以将月份和日期显示为表格的网格。我可以建议使用列表框的列表框构建该表(月/日矩阵)的方式。  1. Xaml代码:

<Window x:Class="SoCalendarHelpAttemptListBoxOfListBoxes.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:soCalendarHelpAttemptListBoxOfListBoxes="clr-namespace:SoCalendarHelpAttemptListBoxOfListBoxes"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate x:Key="MonthDayPresenterDataTemplateKey"
                  DataType="{x:Type soCalendarHelpAttemptListBoxOfListBoxes:DayObject}">
        <Button Command="{Binding CallendarDayCommand}" CommandParameter="{Binding }"  
                Content ="{Binding Day}" Width="30" FontSize="9" Height="15" IsEnabled="{Binding IsEnabled}"></Button>

    </DataTemplate>
    <DataTemplate x:Key="CellTemplateKey" DataType="{x:Type soCalendarHelpAttemptListBoxOfListBoxes:BaseCallendarCellPresenter}">
        <TextBlock Text="{Binding Day}" Height="15" FontSize="9"></TextBlock>
    </DataTemplate>
    <soCalendarHelpAttemptListBoxOfListBoxes:CellTemplateSelector x:Key="SelectorKey" CellTemplate="{StaticResource CellTemplateKey}" DayTemplate="{StaticResource MonthDayPresenterDataTemplateKey}"/>
    <soCalendarHelpAttemptListBoxOfListBoxes:MonthType2BrushConverter x:Key="MonthType2BrushConverter" />
    <DataTemplate x:Key="CallendarTemplateKey" 
                  DataType="{x:Type soCalendarHelpAttemptListBoxOfListBoxes:CalendarViewModel}">
        <ListBox ItemsSource="{Binding MonthObjects}" VerticalContentAlignment="Top">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"></StackPanel>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate DataType="{x:Type soCalendarHelpAttemptListBoxOfListBoxes:MonthObject}">
                                <Grid VerticalAlignment="Top" HorizontalAlignment="Stretch">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"></RowDefinition>
                                        <RowDefinition Height="*"></RowDefinition>
                                    </Grid.RowDefinitions>
                                    <TextBlock Grid.Row="0" Text="{Binding Month}" Foreground="{Binding Month, Converter={StaticResource MonthType2BrushConverter}}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                                    <ListBox Grid.Row="1" ItemsSource="{Binding Days}" >
                                        <ListBox.ItemContainerStyle>
                                            <Style TargetType="ListBoxItem">
                                                <Setter Property="ContentTemplate">
                                                    <Setter.Value>
                                                        <DataTemplate>
                                                            <ContentControl Content="{Binding }" ContentTemplateSelector="{StaticResource SelectorKey}"></ContentControl>
                                                        </DataTemplate>
                                                    </Setter.Value>
                                                </Setter>
                                            </Style>
                                        </ListBox.ItemContainerStyle>
                                    </ListBox>
                                </Grid>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>

    </DataTemplate>
</Window.Resources>
<Window.DataContext>
    <soCalendarHelpAttemptListBoxOfListBoxes:CalendarViewModel/>
</Window.DataContext>
<Grid>
   <ContentControl Content="{Binding }" ContentTemplate="{StaticResource CallendarTemplateKey}"></ContentControl>
</Grid>

 2. ViewModel和模型:

   public class CalendarViewModel:BaseObservableObject
{
    public CalendarViewModel()
    {
        InitMonthCollection();
    }

    private void InitMonthCollection()
    {
        MonthObjects = new ObservableCollection<MonthObject>();
        var monthTypes = Enum.GetValues(typeof (MonthType)).Cast<MonthType>().ToList();
        monthTypes.ForEach(
            month =>
            {
                var monthObject = new MonthObject
                {
                    Month = month,
                };
                monthObject.Days =
                    GetDaysCollection(monthObject);
                MonthObjects.Add(monthObject);
            });
    }

    private ObservableCollection<BaseCallendarCellPresenter> GetDaysCollection(MonthObject month)
    {
        var monthLength = GetMonthLength(month.Month);
        var collection = new ObservableCollection<BaseCallendarCellPresenter>();
        for (var index = 1; index <= monthLength; index++)
        {
            collection.Add(month.Month == MonthType.Days
                ? new BaseCallendarCellPresenter {Day = index.ToString(CultureInfo.InvariantCulture)}
                : new DayObject(OnDaySelectedCommand)
                {
                    Month = month,
                    Day = index.ToString(CultureInfo.InvariantCulture),
                    IsEnabled = true,
                });
        }
        return collection;
    }

    private void OnDaySelectedCommand(DayObject dayObject)
    {

    }

    private static int GetMonthLength(MonthType month)
    {
        int monthLength;
        var key = month;
        switch (key)
        {
            case MonthType.Days:
            case MonthType.Jan:
            {
                monthLength = 31;
            }
                break;
            case MonthType.Feb:
            {
                monthLength = 28;
            }
                break;
            case MonthType.Mar:
            {
                monthLength = 31;
            }
                break;
            case MonthType.Apr:
            {
                monthLength = 30;
            }
                break;
            case MonthType.May:
            {
                monthLength = 31;
            }
                break;
            case MonthType.Jun:
            {
                monthLength = 30;
            }
                break;
            case MonthType.Jul:
            {
                monthLength = 31;
            }
                break;
            case MonthType.Aug:
            {
                monthLength = 31;
            }
                break;
            case MonthType.Sep:
            {
                monthLength = 30;
            }
                break;
            case MonthType.Oct:
            {
                monthLength = 31;
            }
                break;
            case MonthType.Nov:
            {
                monthLength = 30;
            }
                break;
            case MonthType.Dec:
            {
                monthLength = 31;
            }
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
        return monthLength;
    }

    public ObservableCollection<MonthObject> MonthObjects { get; set; }
}

public class MonthObject : BaseObservableObject
{
    private MonthType _month;

    public MonthType Month
    {
        get { return _month; }
        set
        {
            _month = value;
            OnPropertyChanged();
        }
    }

    public ObservableCollection<BaseCallendarCellPresenter> Days { get; set; }
}

public enum MonthType   
{
    Days,
    Jan,
    Feb,
    Mar,
    Apr,
    May,
    Jun,
    Jul,
    Aug,
    Sep,
    Oct,
    Nov,
    Dec,
}

public class BaseCallendarCellPresenter:BaseObservableObject
{
    private string _day;
    public virtual string Day
    {
        get { return _day; }
        set
        {
            _day = value;
            OnPropertyChanged();
        }
    }
}

public class DayObject:BaseCallendarCellPresenter
{
    private readonly Action<DayObject> _onDaySelectedCommand;
    private bool _isEnabled;
    private ICommand _command;
    private MonthObject _month;

    public DayObject(Action<DayObject> onDaySelectedCommand)
    {
        _onDaySelectedCommand = onDaySelectedCommand;
        IsEnabled = false;
    }

    public MonthObject Month
    {
        get { return _month; }
        set
        {
            _month = value;
            OnPropertyChanged();
        }
    }

    public bool IsEnabled   
    {
        get { return _isEnabled; }
        set
        {
            _isEnabled = value;
            OnPropertyChanged();
        }
    }

    public ICommand CallendarDayCommand
    {
        get { return _command ?? (_command = new RelayCommand<DayObject>(_onDaySelectedCommand)); }
    }
}

3。单元格模板选择器代码:

public class CellTemplateSelector : DataTemplateSelector
{
    public DataTemplate DayTemplate { get; set; }
    public DataTemplate CellTemplate { get; set; }
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate template = null;
        if (item is DayObject)
        {
            template = DayTemplate;
        }
        else if(item is BaseCallendarCellPresenter)
        {
            template = CellTemplate;
        }
        return template;
    }
}

4。 MonthType to Brush转换器代码:

public class MonthType2BrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var month = (MonthType)value;
        if (month == MonthType.Days)
            return Brushes.Transparent;
        return Brushes.DarkSlateBlue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

5。 Mvvm零件代码:

public class BaseObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
    {
        var propName = ((MemberExpression)raiser.Body).Member.Name;
        OnPropertyChanged(propName);
    }

    protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, value))
        {
            field = value;
            OnPropertyChanged(name);
            return true;
        }
        return false;
    }
}

public class RelayCommand<T> : ICommand
{
    readonly Action<T> _execute;
    readonly Func<T, bool> _canExecute;

    public event EventHandler CanExecuteChanged;

    public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public void RefreshCommand()
    {
        var cec = CanExecuteChanged;
        if (cec != null)
            cec(this, EventArgs.Empty);
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute == null) return true;
        return _canExecute((T)parameter);
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }
}

public class RelayCommand : RelayCommand<object>
{
    public RelayCommand(Action execute, Func<bool> canExecute = null)
        : base(_ => execute(),
            _ => canExecute == null || canExecute())
    {

    }
}

6。它的外观如何: enter image description here

如果代码有问题我会很高兴,希望它对你有帮助。 问候。