自定义样式WPF TextBox的SelectionStart/CaretIndex始终为0问题
问题原因及解决方案:自定义WPF TextBox样式导致SelectionStart/CaretIndex始终为0
你遇到的这个问题根源在于自定义样式里嵌套了两个TextBox控件——你在XAML里声明的TextBoxInput是外层容器,而实际接收用户输入、维护光标和选择状态的是模板内部的textSource TextBox。当你尝试从TextBoxInput获取SelectionStart或CaretIndex时,你其实是在访问那个从未获得焦点、也没有实际输入内容的外层TextBox的属性,自然会一直返回0。
解决思路一:同步内外层TextBox的光标/选择属性(推荐)
我们可以通过数据绑定,让外层TextBox的SelectionStart、CaretIndex、SelectionLength等属性同步内部textSource的对应状态。修改模板内部的textSource控件,添加属性绑定即可:
<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 --> SelectionStart="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectionStart, Mode=OneWayToSource}" CaretIndex="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CaretIndex, Mode=OneWayToSource}" SelectionLength="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectionLength, Mode=OneWayToSource}">
这样,当用户在输入框中操作光标或选择文本时,内部textSource的状态会自动同步到外层的TextBoxInput,你再通过TextBoxInput.SelectionStart或TextBoxInput.CaretIndex就能获取到正确的值了。
解决思路二:直接访问模板内部的textSource控件
如果不想修改样式,也可以在代码后台通过模板查找内部控件的方式获取光标状态:
// 在需要获取光标位置的方法中调用 var innerTextBox = TextBoxInput.Template.FindName("textSource", TextBoxInput) as TextBox; if (innerTextBox != null) { int currentCaretIndex = innerTextBox.CaretIndex; int currentSelectionStart = innerTextBox.SelectionStart; int currentSelectionLength = innerTextBox.SelectionLength; // 使用获取到的状态做后续逻辑 }
不过这种方法耦合性较高,如果后续修改模板时更改了textSource的名称,代码就会失效,所以优先推荐第一种绑定同步的方案。
内容的提问来源于stack exchange,提问作者Tadej Vengust
相关产品推荐
相关产品推荐

