I have a TextBox input field with a custom style:
<TextBox Style="{StaticResource SettingsTextBoxHint}" KeyDown="textBoxInput_KeyDown" PreviewKeyDown="textBoxInput_PreviewKeyDown" Name="TextBoxInput" Text="{Binding TextBoxInput, Mode=TwoWay}" Tag="{lex:LocText TypeAMessageHere}" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" FontSize="14" HorizontalAlignment="Stretch" VerticalAlignment="Center" VerticalContentAlignment="Center" BorderThickness="0" Margin="0,0,33,0"/>
To which I added the custom style:
<Style TargetType="{x:Type TextBox}" x:Key="SettingsTextBoxHint" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="Border"
BorderThickness="{TemplateBinding BorderThickness}"
Background="White"
Padding="1,2,5,2"
BorderBrush="{StaticResource PrimaryColor}"
ToolTip="{TemplateBinding ToolTip}">
<Grid>
<TextBox Text="{Binding Path=Text,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
x:Name="textSource"
Background="Transparent"
BorderBrush="Transparent"
TextWrapping="{TemplateBinding TextWrapping}"
Panel.ZIndex="2"
FontSize="12">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="Border"
Background="Transparent"
BorderBrush="Transparent"
CornerRadius="0">
<ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
</TextBox>
<TextBox Margin="0,3,0,0" BorderThickness="0" Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="FontFamily" Value="{StaticResource RobotoRegularFont}" />
<Setter Property="Foreground" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
<Setter Property="Foreground" Value="#cccccc"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="BorderBrush" Value="DarkGray"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="textSource" Property="FocusManager.FocusedElement" Value="{Binding ElementName=textSource}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The point of which is to make the TextBox transparent and to add hint functionality which text is set trough Tag.
Everything works exactly as I want. The problem I have is that I am writing a new functionality in which I need the position of cursor in the TextBox. But SelectionStart or CaretIndex always return 0 value. If I remove my style I get the correct value.
Can anyone tell me what I missed?
The problem is that you are using a TextBox
within a TextBox
. The user interacts with the inner text box, whose text, caret position, etc. are in no way related to the outer text box.
Let me clean up your style for you:
<Style x:Key="SettingsTextBoxHint"
TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="BorderBrush"
Value="{StaticResource PrimaryColor}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="Border"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
Padding="{TemplateBinding Padding}">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Center" />
<TextBlock x:Name="Hint"
Margin="3,1"
Text="{TemplateBinding Tag}"
FontStyle="Italic"
Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"
Visibility="Hidden" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border"
Property="Background"
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter TargetName="Hint" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To find the cursor position within the TextBox
, you can use Mouse.GetPosition(your_text_box)
. To get the caret position within the text, use the CaretIndex
property. Note, however, that CaretIndex
is *not* a dependency property, so it does not raise change notifications. Thus, you cannot bind to it and expect the binding target to be updated.