I am creating a textbox style that extends the Custom Picker Demo in order to implement validation. If a user were to to enter an invalid date, an error icon pops up that provides tooltip information.
Private Sub CompletionValidation(sender As Object, e As RoutedEventArgs) Dim tbox As TextBox = DirectCast(sender, TextBox) If IsDate(tbox.Text) Then If CType(validationState(tbox.Name), ValidationStates) <> ValidationStates.OK Then tbox.Style = DirectCast(FindResource("tbCalendarNormalStyle"), Style) End If validationState(tbox.Name) = ValidationStates.OK Else If CType(validationState(tbox.Name), ValidationStates) <> ValidationStates.[ERROR] Then tbox.Style = DirectCast(FindResource("tbCalendarErrorStyle"), Style)
' Very important if want to use Template.FindName when changing style dynamically! validationState(tbox.Name) = ValidationStates.[ERROR] tbox.UpdateLayout() End If
' Fetch the errorimage in the tbox:s control template.. Dim errImg As Image = DirectCast(tbox.Template.FindName("ErrorImage", tbox), Image) ' If regex dont allow empty field.. put alternative message that "this field are required". errImg.ToolTip = If(tbox.Text.Trim().Equals([String].Empty), fieldRequired, DirectCast(errorMessage(DirectCast(tbox.Tag, String)), String)) End If End Sub
The styles and tooltips display correctly when tested independtly, however when the style is changed at runtime (line 11), I receive the error: 'PopUpImageButton' name cannot be found in the name scope of 'System.Windows.Controls.Calendar'.
My assumption is that it is something associated with the storyboard, and this blog post suggests that it has to do with way order of event execution in a multi-threaded environment.
And the relevant styles:
<Converter:CalendarConverter x:Key="calendarConverter" /><ControlTemplate x:Key="IconButton" TargetType="{x:Type ToggleButton}"><Border><ContentPresenter /></Border></ControlTemplate><Style x:Key="tbCalendarNormalStyle" TargetType="{x:Type TextBox}"><Setter Property="FontFamily" Value="Arial"/><Setter Property="FontSize" Value="16"/><Setter Property="ForceCursor" Value="False"/><Setter Property="Foreground" Value="{StaticResource TextColor}"/><Setter Property="FontWeight" Value="Bold"/><Setter Property="HorizontalContentAlignment" Value="Left"/><Setter Property="VerticalContentAlignment" Value="Center"/><Setter Property="Padding" Value="3,0,3,0"/><Setter Property="Margin" Value="2"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type TextBox}"><Grid><Border Background="{StaticResource TextBackColor}" BorderBrush="{StaticResource BorderColor}" x:Name="Bd" CornerRadius="4" BorderThickness="2"><ScrollViewer Margin="0" x:Name="PART_ContentHost" /></Border><ToggleButton Template="{StaticResource IconButton}" MaxHeight="21" Margin="-1,0,4,0" Name="PopUpImageButton" Focusable="False" IsChecked="False"><Image Source="/AddTeamMemberTest;component/Images/Calendar_Icon.png" Stretch="Uniform" Visibility="Hidden" HorizontalAlignment="Right" Name="imgPicker" ></Image></ToggleButton><Popup IsOpen="{Binding Path=IsChecked, ElementName=PopUpImageButton, Mode=TwoWay}" x:Name="CustomPopup" Margin="0,-1,0,0" PopupAnimation="Fade" StaysOpen="False"><Calendar Margin="0,-1,0,0" x:Name="CalDisplay" SelectedDate="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Text, Mode=TwoWay, Converter={StaticResource calendarConverter}}" Focusable="False" DisplayDate="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Text, Mode=OneWay, Converter={StaticResource calendarConverter}}" ><Control.Triggers><EventTrigger RoutedEvent="Calendar.SelectedDatesChanged"><BeginStoryboard><Storyboard><BooleanAnimationUsingKeyFrames Storyboard.TargetName="PopUpImageButton" Storyboard.TargetProperty="IsChecked"><DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False"></DiscreteBooleanKeyFrame></BooleanAnimationUsingKeyFrames></Storyboard></BeginStoryboard></EventTrigger></Control.Triggers></Calendar></Popup></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="true"><Setter Property="Visibility" TargetName="imgPicker" Value="Visible" /></Trigger><Trigger Property="IsFocused" Value="true"><Setter Property="Visibility" TargetName="imgPicker" Value="Visible" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style><Style x:Key="tbCalendarErrorStyle" TargetType="{x:Type TextBox}"><Setter Property="FontFamily" Value="Arial"/><Setter Property="FontSize" Value="16"/><Setter Property="ForceCursor" Value="False"/><Setter Property="Foreground" Value="{StaticResource TextColor}"/><Setter Property="FontWeight" Value="Bold"/><Setter Property="HorizontalContentAlignment" Value="Left"/><Setter Property="VerticalContentAlignment" Value="Center"/><Setter Property="Padding" Value="3,0,3,0"/><Setter Property="Margin" Value="2"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type TextBox}"><Grid><Border Background="{StaticResource TextBackColor}" BorderBrush="#d99" x:Name="Bd" CornerRadius="4" BorderThickness="2"><ScrollViewer Margin="0" x:Name="PART_ContentHost" /></Border><Image Name="ErrorImage" Width="24" Height="24" Margin="0,0,4,0" Source="/AddTeamMemberTest;component/Images/error.png" HorizontalAlignment="Right"/><ToggleButton Template="{StaticResource IconButton}" MaxHeight="21" Margin="-1,0,30,0" Name="PopUpImageButton" Focusable="False" IsChecked="False"><Image Source="/AddTeamMemberTest;component/Images/Calendar_Icon.png" Stretch="Uniform" Visibility="Hidden" HorizontalAlignment="Right" Name="imgPicker" ></Image></ToggleButton><Popup IsOpen="{Binding Path=IsChecked, ElementName=PopUpImageButton, Mode=TwoWay}" x:Name="CustomPopup" Margin="0,-1,0,0" PopupAnimation="Fade" StaysOpen="False"><Calendar Margin="0,-1,0,0" x:Name="CalDisplay" SelectedDate="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Text, Mode=TwoWay, Converter={StaticResource calendarConverter}}" Focusable="False" DisplayDate="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Text, Mode=OneWay, Converter={StaticResource calendarConverter}}" ><Control.Triggers><EventTrigger RoutedEvent="Calendar.SelectedDatesChanged"><BeginStoryboard><Storyboard><BooleanAnimationUsingKeyFrames Storyboard.TargetName="PopUpImageButton" Storyboard.TargetProperty="IsChecked"><DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False"></DiscreteBooleanKeyFrame></BooleanAnimationUsingKeyFrames></Storyboard></BeginStoryboard></EventTrigger></Control.Triggers></Calendar></Popup></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="true"><Setter Property="Visibility" TargetName="imgPicker" Value="Visible" /></Trigger><Trigger Property="IsFocused" Value="true"><Setter Property="Visibility" TargetName="imgPicker" Value="Visible" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>
Help would be appreciated.