0

I have been working on this problem for a while now, I would like to add a validation rule to my DatePicker that will make sure the SelectedDate is between two dates (Upper and Lower limits). I would also like these two limits to be data bound to other elements, the example I am working with an employee cannot have a birth date before they joined a company for eg. Here are my classes: LimitDates:

Public Class LimitDates
    Inherits DependencyObject

    Public Shared ReadOnly UpperLimitDateProperty As DependencyProperty
    Public Shared ReadOnly LowerLimitDateProperty As DependencyProperty

    Shared Sub New()
        Dim metadata As New FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.None)
        UpperLimitDateProperty = DependencyProperty.Register("UpperLimitDate", GetType(Date), GetType(LimitDates))
        LowerLimitDateProperty = DependencyProperty.Register("LowerLimitDate", GetType(Date), GetType(LimitDates))
    End Sub

    Public Property UpperLimitDate As Nullable(Of DateTime)
        Get
            Return CType(GetValue(UpperLimitDateProperty), Nullable(Of DateTime))
        End Get
        Set(value As Nullable(Of DateTime))
            SetValue(UpperLimitDateProperty, value)
        End Set
    End Property

    Public Property LowerLimitDate As Nullable(Of DateTime)
        Get
            Return CType(GetValue(LowerLimitDateProperty), Nullable(Of DateTime))
        End Get
        Set(value As Nullable(Of DateTime))
            SetValue(LowerLimitDateProperty, value)
        End Set
    End Property

End Class

DateValidationRule:

Public Class DateValidationRule
    Inherits ValidationRule

    Public Property FutureDateAllowed As Boolean = True
    Public Property LimitDates As LimitDates


    Public Overloads Overrides Function Validate(value As Object, cultureInfo As CultureInfo) As Windows.Controls.ValidationResult
        Try
            Dim d As Date = CDate(value)
            If Not FutureDateAllowed And d > Now Then
                Return New System.Windows.Controls.ValidationResult(False, "Future dates not allowed")
            End If
            If Not LimitDates Is Nothing Then
                If Not LimitDates.LowerLimitDate Is Nothing Then
                    If d < LimitDates.LowerLimitDate Then
                        Return New System.Windows.Controls.ValidationResult(False, "Date must less then " & LimitDates.LowerLimitDate)
                    End If
                End If
                If Not LimitDates.UpperLimitDate Is Nothing Then
                    If d > LimitDates.UpperLimitDate Then
                        Return New System.Windows.Controls.ValidationResult(False, "Date must not be behond " & LimitDates.UpperLimitDate)
                    End If
                End If
            End If
        Catch ex As Exception
            Return New System.Windows.Controls.ValidationResult(False, "Not in correct format, please input a correct date. Eg. 23-04-2012")
        End Try

        ' If hasn't returned an error already, must be okay
        Return New System.Windows.Controls.ValidationResult(True, Nothing)
    End Function

End Class

And XAML markup for EmployeeView:

<Label Style="{StaticResource EditViewLabel}" Grid.Row="0">Birth Date</Label>
<DatePicker Grid.Row="0" Grid.Column="1" x:Name="dtPkBirthDate" DisplayDateEnd="{Binding ElementName=dtPkStartDate, Path=SelectedDate}">
<DatePicker.SelectedDate>
<Binding Path="Employee.DateOfBirth">
<Binding.ValidationRules>
<local:DateValidationRule FutureDateAllowed="True">
<local:DateValidationRule.LimitDates>
<local:LimitDates UpperLimitDate="4/5/2010" />
      </local:DateValidationRule.LimitDates>    
</local:DateValidationRule>
</Binding.ValidationRules>
</Binding>
</DatePicker.SelectedDate>
</DatePicker>

It all looks fine to me, and it does work if the date is hard coded, but when I try binding to another control or to a property of the DataContext, the Limit date value is never set, only the default value of 12:00AM appears in the debugger.

Also how can I set and check if dates are null (VB.net not C# with I am used to)?

Thanks. Luke

Edit:

Okay so I think I might have worked out a little bit of why, after reading Binding ElementName. Does it use Visual Tree or Logical Tree and http://social.msdn.microsoft.com/Forums/vstudio/en-US/e359b99f-e864-4e9e-b81e-2692f240598f/binding-to-object-in-template-in-another-visual-tree?forum=wpf I think that the binding on DateValidationRule might not be finding the ElementName as both element's are siblings and so in a different visual tree..?

I will keep researching

Community
  • 1
  • 1
Luke T O'Brien
  • 2,565
  • 3
  • 26
  • 38
  • user can't have birthday before he joined to the company sounds fun :) – Arsen Mkrtchyan Mar 20 '14 at 10:44
  • 1
    Date of Birth, they cannot join the company when they haven't been born yet :P – Luke T O'Brien Mar 20 '14 at 10:55
  • Don't post your whole code. Just post the relevant code. Check [this post](http://meta.stackexchange.com/questions/225698/is-it-correct-to-post-whole-of-the-code-in-question). It isn't safe every time and it's difficult for readers to read too. – Kashish Arora Mar 20 '14 at 11:46
  • I think I've found an answer "ValidationRule is not a dependency object (nor is it in the element tree), so you cannot set bindings on dependency properties on it (nor would they be resolved if you could)." [link] (http://social.msdn.microsoft.com/Forums/vstudio/en-US/75d0bd00-23af-43e4-ac9e-5d29f4a51102/custom-validationrule-data-binding-property) but let's see if there's an alternative way of doing this – Luke T O'Brien Mar 20 '14 at 12:21

1 Answers1

0

Yup, I'm going with my answer I found... it's impossible!

"ValidationRule is not a dependency object (nor is it in the element tree), so you cannot set bindings on dependency properties on it (nor would they be resolved if you could)." MSDN

I've moved on to using the Infragistics XamDateTimeInput (Which says it's for Silverlight but is also here for WPF). Still doesn't have the validation I want, but I am happy using Value Converters and Business Logic validation.

Thanks

Luke T O'Brien
  • 2,565
  • 3
  • 26
  • 38