无法找到一种方法来自定义WPF日历控件以在一列中显示一个月的日期。任何想法如何以优雅的方式实现这一目标?
╔════════╦═════╦═════╦═════╦════╗
║ ║ Jan ║ Feb ║ Mar ║ .. ║
╠════════╬═════╬═════╬═════╬════╣
║ #1 ║ ║ ║ ║ ║
║ #2 ║ ║ ║ ║ ║
║ #3 ║ ║ ║ ║ ║
║ .. ║ ║ ║ ║ ║
║ #30 ║ ║ ║ ║ ║
╚════════╩═════╩═════╩═════╩════╝
答案 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())
{
}
}
如果代码有问题我会很高兴,希望它对你有帮助。 问候。