I've encountered some kind of binding error in my program, which I can't explain by myself.
I wanted to style a TextBox
, so that it displays a warning icon if the value is not covered by some product specification. When the user hovers the cursor over the icon, a more detailed warning message should appear in an AdornerLayer
.
As you can see, the control works, but I still have a question about it. To describe my problem, I have reduced the code to its absolute minimum:
My code
App.xaml
<Application x:Class="WpfApplication3.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ThemesAero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="22" />
<RowDefinition />
</Grid.RowDefinitions>
<ThemesAero:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ThemesAero:ListBoxChrome>
<Image Name="WarningIcon" Margin="5,0,0,0" Grid.Column="1" RenderOptions.BitmapScalingMode="HighQuality" Source="warning_256x256.png" />
<Border x:Name="InformationBorder" Background="#E1BA18" Margin="5,0,0,0" Grid.Row="1" Grid.ColumnSpan="2" Opacity="0" CornerRadius="1.5" IsHitTestVisible="False" MinHeight="24" MaxWidth="267" VerticalAlignment="Bottom" HorizontalAlignment="Left">
<TextBlock Text="This is some warning message." Foreground="White" Margin="8,3,8,3" TextWrapping="Wrap"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=WarningIcon, Path=IsMouseOver}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="fadeInStoryboard">
<Storyboard>
<DoubleAnimation Duration="00:00:00.15" Storyboard.TargetName="InformationBorder" Storyboard.TargetProperty="Opacity" To="1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeInStoryboard"/>
<BeginStoryboard x:Name="fadeOutStoryBoard">
<Storyboard>
<DoubleAnimation Duration="00:00:00.15" Storyboard.TargetName="InformationBorder" Storyboard.TargetProperty="Opacity" To="0"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
MainWindow.xaml
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl>
<TabItem Header="Debug 1">
<TextBox Height="80" Width="150" />
</TabItem>
<TabItem Header="Debug 2">
<TextBox Height="80" Width="150" />
</TabItem>
</TabControl>
</Grid>
</Window>
What is my problem exactly?
What do we have here? I've applied the Style
to two TextBox
es in a TabControl
.
On the first TabItem
(Debug 1), the IsMouseOver trigger works just fine and fades the warning message in and out.
However, an identical TextBox
on the second TabItem
(Debug 2) throws the following error and the IsMouseOver trigger isn't working at all.
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=WarningIcon'. BindingExpression:Path=IsMouseOver; DataItem=null; target element is 'TextBox' (Name=''); target property is 'NoTarget' (type 'Object')
What have I tried to solve the problem?
As I read some suggested solutions on how to fix this, I finally noticed that all of the following triggers are working fine:
<DataTrigger Binding="{Binding ElementName=WarningIcon, Path=IsMouseOver}" Value="True">
<Setter TargetName="InformationBorder" Property="Opacity" Value="1" />
</DataTrigger>
--
<Trigger SourceName="WarningIcon" Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard x:Name="fadeInStoryboard">
<Storyboard>
<DoubleAnimation Duration="00:00:00.15" Storyboard.TargetName="InformationBorder" Storyboard.TargetProperty="Opacity" To="1"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeInStoryboard"/>
<BeginStoryboard x:Name="fadeOutStoryBoard">
<Storyboard>
<DoubleAnimation Duration="00:00:00.15" Storyboard.TargetName="InformationBorder" Storyboard.TargetProperty="Opacity" To="0"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
--
<Trigger SourceName="WarningIcon" Property="IsMouseOver" Value="True">
<Setter TargetName="InformationBorder" Property="Opacity" Value="1" />
</Trigger>
This error only occurs when I use a DataTrigger
with two Storyboard
s in a TabControl
, but why?
I already know how to fix this, so I'm just interested what's happening behind the scenes.