Class ViewModel
Inherits INotifyPropertyChanged
Private selectedDate As DateTime
Public Property SelectedDate As DateTime
Get
Return Me.selectedDate
End Get
Set(ByVal value As DateTime)
If value < DateTime.Today Then
Throw New ArgumentException("Date can't be in the past.")
End If
Me.selectedDate = value
OnPropertyChanged()
End Set
End Property
Public ReadOnly Property ResetDateCommand As ICommand
Get
Return New RelayCommand(AddressOf ExecuteResetDate)
End Get
End Property
Public Sub New()
Me.SelectedDate = DateTime.Today
End Sub
Public Sub ExecuteResetDate(ByVal commandParameter As Object)
Return CSharpImpl.__Assign(Me.SelectedDate, DateTime.Today)
End Sub
End Class
MainWindow.xaml
<Window>
<Window.Resources>
<ViewModel />
</Window.Resources>
<StackPanel x:Name="RootPanel" viewModels:Item.IsMarkedAsRead="True">
<Button Content="Reset Date"
Visibility="{Binding ElementName=DatePicker, Path=(Validation.HasError), Converter={StaticResource BooleanToVisibilityConverter}}"
Command="{Binding ResetDateCommand}" />
<DatePicker x:Name="DatePicker"
SelectedDate="{Binding SelectedDate, ValidatesOnExceptions=True}"
SelectedDateFormat="Short" />
</StackPanel>
</Window>
Замечания
Лучшая практика в дизайне пользовательского интерфейса - всегда предотвращать неправильный ввод. Если возможно, вы не должны разрешать недопустимый ввод, например, отключая кнопки, скрывая недопустимые параметры, ограничивая диапазоны и т. Д. c. Не позволяйте пользователю выбирать недопустимые параметры. Это приводит к разочарованию пользователей. Один из способов предотвратить неправильный ввод - использовать специальные элементы управления. Вместо того, чтобы заставлять пользователя вводить дату, вы предлагаете DatePicker
. Это исключает опечатки. Но он также может устранить неправильный выбор, предоставив только действительные даты.
Если вы хотите запретить выбор дат в прошлом, вы можете сузить диапазон выбора:
<!-- Only show dates from today -->
<DatePicker DisplayDateStart="{x:Static system:DateTime.Today}" />
Если у вас есть дополнительные недопустимые даты, например праздники, вы можете определить набор этих дат, установив свойство DatePicker.BlackoutDates
:
DatePickerHelper.cs
Class DatePickerHelper
Inherits DependencyObject
Public Shared ReadOnly BlackedDaysProperty As DependencyProperty = DependencyProperty.RegisterAttached("BlackedDays", GetType(IEnumerable(Of CalendarDateRange)), GetType(DatePickerHelper), New PropertyMetadata(Nothing, AddressOf DatePickerHelper.OnBlackDatesChanged))
Public Shared Sub SetBlackedDays(ByVal attachingElement As DependencyObject, ByVal value As IEnumerable(Of CalendarDateRange))
Return attachingElement.SetValue(DatePickerHelper.BlackedDaysProperty, value)
End Sub
Public Shared Function GetBlackedDays(ByVal attachingElement As DependencyObject) As IEnumerable(Of CalendarDateRange)
Return CType(attachingElement.GetValue(DatePickerHelper.BlackedDaysProperty), IEnumerable(Of CalendarDateRange))
End Function
Private Shared ReadOnly Property DatePickerTable As Dictionary(Of INotifyCollectionChanged, DatePicker)
Private Shared Sub New()
DatePickerHelper.DatePickerTable = New Dictionary(Of INotifyCollectionChanged, DatePicker)()
End Sub
Private Shared Sub OnBlackDatesChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim attachedDatePicker = TryCast(d, DatePicker)
Dim oldObservableCollection As INotifyCollectionChanged = Nothing
If CSharpImpl.__Assign(oldObservableCollection, TryCast(e.OldValue, INotifyCollectionChanged)) IsNot Nothing Then
oldObservableCollection.CollectionChanged -= AddressOf UpdateDatePickerBlockedDates
DatePickerHelper.DatePickerTable.Remove(oldObservableCollection)
End If
Dim newObservableCollection As INotifyCollectionChanged = Nothing
If CSharpImpl.__Assign(newObservableCollection, TryCast(e.NewValue, INotifyCollectionChanged)) IsNot Nothing Then
newObservableCollection.CollectionChanged += AddressOf UpdateDatePickerBlockedDates
DatePickerHelper.DatePickerTable.Add(newObservableCollection, attachedDatePicker)
End If
attachedDatePicker.BlackoutDates.AddRange(TryCast(e.NewValue, IEnumerable(Of CalendarDateRange)))
End Sub
Private Shared Sub UpdateDatePickerBlockedDates(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)
Dim attachedDatePicker As DatePicker = Nothing
If Not DatePickerHelper.DatePickerTable.TryGetValue(TryCast(sender, INotifyCollectionChanged), attachedDatePicker) Then
Return
End If
Select Case e.Action
Case NotifyCollectionChangedAction.Add
attachedDatePicker.BlackoutDates.AddRange(e.NewItems.OfType(Of CalendarDateRange)())
Case NotifyCollectionChangedAction.Remove, NotifyCollectionChangedAction.Replace
e.OldItems.OfType(Of CalendarDateRange)().ToList().ForEach(Function(removedItem) attachedDatePicker.BlackoutDates.Remove(removedItem))
Case NotifyCollectionChangedAction.Move
Case NotifyCollectionChangedAction.Reset
attachedDatePicker.BlackoutDates.Clear()
Case Else
End Select
End Sub
End Class
ViewModel.cs
Class ViewModel
Public Property BlockedDates As ObservableCollection(Of CalendarDateRange)
// Block Christmas holidays and all days in the past
Public Sub New()
Return CSharpImpl.__Assign(Me.BlockedDates, New ObservableCollection(Of CalendarDateRange) From {
New CalendarDateRange(New DateTime(2020, 12, 24), New DateTime(2020, 12, 26)),
New CalendarDateRange(DateTime.MinValue, DateTime.Today.Subtract(TimeSpan.FromDays(1)))
})
End Sub
End Class
MainWindow.xaml
<!-- Only show dates from today -->
<DatePicker DatePickerHelper.BlackedDays="{Binding BlockedDates}" />