除了VerticalScrollBar的宽度,如何获取TextBox的内容宽度?
How to get the content width of the TextBox except for width of the VerticalScrollBar?
我创建了派生 TextBox 的 HighlightTextBox。代码如下所示。
<Style TargetType="{x:Type host:HighlightTextBox}">
<Setter Property="AcceptsReturn" Value="True" />
<Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="Foreground" Value="#00000000"/>
<Setter Property="FontSize" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=FontSize, Mode=TwoWay}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate x:Name="textArea" TargetType="{x:Type host:HighlightTextBox}">
<Border BorderThickness="{Binding BorderTickness}"
BorderBrush="{Binding BorderBrush}"
Background="{Binding BackGround}">
<Grid Margin="{TemplateBinding Padding}" x:Name="PART_Grid">
<host:TextCanvas x:Name="PART_RenderCanvas" ClipToBounds="True"
TextOptions.TextRenderingMode="ClearType" TextOptions.TextFormattingMode="Display"
LineHeight="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=LineHeight}"/>
<ScrollViewer x:Name="PART_ContentHost" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
重点是ControlTemplate。
可以看到,HighlightTextBox的内容由TextCanvas和ScrollViewer组成。
HighlightTextBox 通过在 TextCanvas 上绘制来突出显示当前选定的行,但它侵入了 VerticalScrollViewer 部分,如下所示。
我想在不侵入VerticalScrollViewer的情况下显示
我认为可能是 TextCanvas 占据了 TextBox 的整个部分。
所以我尝试将 TextCanvas 移动到 ScrollViewer 中,但这样会面临 运行 时间错误,即“PART_ContentHost 不能有子元素。
我认为另一种方法是获取除VerticalScrollBar 宽度之外的TextBox 的内容宽度并将其绑定到TextCanvas 的宽度。但是不知道怎么获取。
我应该怎么做才能解决这个问题?
如果您有更好的方法或其他解决方法,请告诉我。
感谢您的阅读。
Search the visual tree 对于您的 ScrollViewer 的内容展示器,这将为您提供内容区域本身的宽度:
var scrollViewer = yourTextBox.Template.FindName("PART_ContentHost", yourTextBox) as ScrollViewer;
var contentPresenter = UIHelper.FindChild<ScrollContentPresenter>(scrollViewer, String.Empty);
var width = contentPresenter.ActualWidth;
更新:您可以像这样直接绑定到 ScrollContentPresenter 的内容控件:
<Grid Margin="{TemplateBinding Padding}" x:Name="PART_Grid">
<TextBlock Text="{Binding ElementName=PART_ContentHost, Path=Content.ActualWidth}" Background="CornflowerBlue" VerticalAlignment="Top"/>
<ScrollViewer x:Name="PART_ContentHost" />
</Grid>
请记住,这会为您提供 ScrollViewers content 宽度的区域,在我上面给出的示例中,由于事实上,ScrollViewers 内容是一个具有 2,0,2,0 边距的 TextBoxView:
为了弥补这一点,您可能需要将 Canvas 边距绑定到 TextBoxView 边距(在我的例子中是 TextBlock 而不是 Canvas):
<Grid Margin="{TemplateBinding Padding}" x:Name="PART_Grid">
<TextBlock Text="{Binding ElementName=PART_ContentHost, Path=Content.ActualWidth}"
Margin="{Binding ElementName=PART_ContentHost, Path=Content.Margin}"
Background="CornflowerBlue" VerticalAlignment="Top" />
<ScrollViewer x:Name="PART_ContentHost" Padding="0" Margin="0"/>
</Grid>
这将使您的 Canvas 在父网格中的对齐方式与 TextBoxView 的对齐方式相同,以便一切都正确排列:
(您也可以只删除 TextBoxView 的边距,但这可能不是您想要的)。
我创建了派生 TextBox 的 HighlightTextBox。代码如下所示。
<Style TargetType="{x:Type host:HighlightTextBox}">
<Setter Property="AcceptsReturn" Value="True" />
<Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="Foreground" Value="#00000000"/>
<Setter Property="FontSize" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=FontSize, Mode=TwoWay}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate x:Name="textArea" TargetType="{x:Type host:HighlightTextBox}">
<Border BorderThickness="{Binding BorderTickness}"
BorderBrush="{Binding BorderBrush}"
Background="{Binding BackGround}">
<Grid Margin="{TemplateBinding Padding}" x:Name="PART_Grid">
<host:TextCanvas x:Name="PART_RenderCanvas" ClipToBounds="True"
TextOptions.TextRenderingMode="ClearType" TextOptions.TextFormattingMode="Display"
LineHeight="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=LineHeight}"/>
<ScrollViewer x:Name="PART_ContentHost" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
重点是ControlTemplate。 可以看到,HighlightTextBox的内容由TextCanvas和ScrollViewer组成。
HighlightTextBox 通过在 TextCanvas 上绘制来突出显示当前选定的行,但它侵入了 VerticalScrollViewer 部分,如下所示。
我想在不侵入VerticalScrollViewer的情况下显示
我认为可能是 TextCanvas 占据了 TextBox 的整个部分。 所以我尝试将 TextCanvas 移动到 ScrollViewer 中,但这样会面临 运行 时间错误,即“PART_ContentHost 不能有子元素。
我认为另一种方法是获取除VerticalScrollBar 宽度之外的TextBox 的内容宽度并将其绑定到TextCanvas 的宽度。但是不知道怎么获取。
我应该怎么做才能解决这个问题? 如果您有更好的方法或其他解决方法,请告诉我。
感谢您的阅读。
Search the visual tree 对于您的 ScrollViewer 的内容展示器,这将为您提供内容区域本身的宽度:
var scrollViewer = yourTextBox.Template.FindName("PART_ContentHost", yourTextBox) as ScrollViewer;
var contentPresenter = UIHelper.FindChild<ScrollContentPresenter>(scrollViewer, String.Empty);
var width = contentPresenter.ActualWidth;
更新:您可以像这样直接绑定到 ScrollContentPresenter 的内容控件:
<Grid Margin="{TemplateBinding Padding}" x:Name="PART_Grid">
<TextBlock Text="{Binding ElementName=PART_ContentHost, Path=Content.ActualWidth}" Background="CornflowerBlue" VerticalAlignment="Top"/>
<ScrollViewer x:Name="PART_ContentHost" />
</Grid>
请记住,这会为您提供 ScrollViewers content 宽度的区域,在我上面给出的示例中,由于事实上,ScrollViewers 内容是一个具有 2,0,2,0 边距的 TextBoxView:
为了弥补这一点,您可能需要将 Canvas 边距绑定到 TextBoxView 边距(在我的例子中是 TextBlock 而不是 Canvas):
<Grid Margin="{TemplateBinding Padding}" x:Name="PART_Grid">
<TextBlock Text="{Binding ElementName=PART_ContentHost, Path=Content.ActualWidth}"
Margin="{Binding ElementName=PART_ContentHost, Path=Content.Margin}"
Background="CornflowerBlue" VerticalAlignment="Top" />
<ScrollViewer x:Name="PART_ContentHost" Padding="0" Margin="0"/>
</Grid>
这将使您的 Canvas 在父网格中的对齐方式与 TextBoxView 的对齐方式相同,以便一切都正确排列:
(您也可以只删除 TextBoxView 的边距,但这可能不是您想要的)。