An interface with disabled controls, without any discernible reason why they are disabled, might be confusing to the applications user. Tooltips can prevent this, but adding a second tooltip for a disabled control will result in XAML bloat. In this blog post i describe an alternative to have two tooltips on one control, without the overhead.
If you want to add a tooltip to a control in XAML, and a second tooltip to show when that control is disabled, the simplest way is to add a style, as shown here:
<Button x:Name="btnClearAll" DockPanel.Dock="Left" Content="Clear _All"
IsEnabled="{Binding ElementName=lbSelectedFiles, Path=HasItems}" Padding="10,0" TabIndex="2" VerticalAlignment="Bottom">
<Button.Style>
<Style TargetType="Button">
<Setter Property="ToolTip" Value="Remove all files from the list" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="ToolTip" Value="No files in the list"/>
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
While this might be just fine for a single tooltip, a window with a lot of controls would add up to a LOT of extra XAML. I decided to look something more compact. One possibility I considered was to make a new dependency property and manipulate the tooltip text that way. But after reading up on that i decided there were two reasons to not do so:
1- It would have gotten pretty complicated,
2- it would not have fitted in smoothly with the existing property.
What i came up with is more elegant and a lot simpler: I used a converter to assign the tooltip text. Unfortunately a converter does not have (that I know of) a convenient way to tell which control called it, so I included the name of the caller in the parameter:
<Window.Resources>
<local:FetchToolTip x:Key="ToolTipProvider"/>
</Window.Resources>
<Button x:Name="btnClearSelected" Content ="Remove Selected"
ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled,
Converter={StaticResource ToolTipProvider}, ConverterParameter=btnClearSelected}">
</Button>
The class FetchToolTip gets the tooltip form the project resources, based on the name of the caller and the value of the boolean:
Public Class FetchToolTip
Implements IValueConverter
Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
Dim bEnabled As Boolean
Dim strName As String
Dim strToolTip As String
Try
bEnabled = CBool(value)
strName = CStr(parameter)
If (bEnabled) Then
strToolTip = My.Resources.ResourceManager.GetString(strName)
Else
strToolTip = My.Resources.ResourceManager.GetString(strName & "_Disabled")
End If
Return strToolTip
Catch ex As Exception
MsgBox("exception in ToolTipProvider")
Debug.Write(Utilities.GetExceptionInfo(ex))
End Try
Return "Tooltip not found."
End Function
Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
Throw New NotImplementedException
End Function
End Class
The last bit of the puzzle then is to add some strings to our project to be used for the tooltip:
And Voila! Two tooltips per control, with overhead included only once!
Hope this helps someone, and have fun coding!
