当文本不再适合一行时,如何将 TextBox 控件配置为自动垂直调整自身大小? [英] How do I configure a TextBox control to automatically resize itself vertically when text no longer fits on one line?
问题描述
当文本不再适合一行时,如何配置 TextBox
控件以自动调整其自身的垂直大小?
How do I configure a TextBox
control to automatically resize itself vertically when text no longer fits on one line?
例如,在以下 XAML 中:
For example, in the following XAML:
<DockPanel LastChildFill="True" Margin="0,0,0,0">
<Border Name="dataGridHeader"
DataContext="{Binding Descriptor.Filter}"
DockPanel.Dock="Top"
BorderThickness="1"
Style="{StaticResource ChamelionBorder}">
<Border
Padding="5"
BorderThickness="1,1,0,0"
BorderBrush="{DynamicResource {ComponentResourceKey TypeInTargetAssembly=dc:NavigationPane,
ResourceId={x:Static dc:NavigationPaneColors.NavPaneTitleBorder}}}">
<StackPanel Orientation="Horizontal">
<TextBlock
Name="DataGridTitle"
FontSize="14"
FontWeight="Bold"
Foreground="{DynamicResource {ComponentResourceKey
TypeInTargetAssembly=dc:NavigationPane,
ResourceId={x:Static dc:NavigationPaneColors.NavPaneTitleForeground}}}"/>
<StackPanel Margin="5,0" Orientation="Horizontal"
Visibility="{Binding IsFilterEnabled, FallbackValue=Collapsed, Mode=OneWay, Converter={StaticResource BooleanToVisibility}}"
IsEnabled="{Binding IsFilterEnabled, FallbackValue=false}" >
<TextBlock />
<TextBox
Name="VerticallyExpandMe"
Padding="0, 0, 0, 0"
Margin="10,2,10,-1"
AcceptsReturn="True"
VerticalAlignment="Center"
Text="{Binding QueryString}"
Foreground="{DynamicResource {ComponentResourceKey
TypeInTargetAssembly=dc:NavigationPane,
ResourceId={x:Static dc:NavigationPaneColors.NavPaneTitleForeground}}}">
</TextBox>
</StackPanel>
</StackPanel>
</Border>
</Border>
</DockPanel>
名为VerticallyExpandMe"的TextBox
控件需要在绑定到它的文本不适合一行时自动垂直扩展.将 AcceptsReturn
设置为 true,TextBox
如果我在其中按 Enter 会垂直扩展,但我希望它自动执行此操作.
The TextBox
control named "VerticallyExpandMe" needs to automatically expand vertically when the text bound to it does not fit on one line. With AcceptsReturn
set to true, TextBox
expands vertically if I press enter within it, but I want it do do this automatically.
推荐答案
尽管 Andre Luus 的建议基本上是正确的,但在这里实际上行不通,因为您的布局会破坏文本换行.我会解释原因.
Although Andre Luus's suggestion is basically correct, it won't actually work here, because your layout will defeat text wrapping. I'll explain why.
从根本上说,问题在于:文本换行仅在元素宽度受限时执行任何操作,但您的 TextBox
具有不受约束的宽度,因为它是水平 StackPanel
的后代.(嗯,两个水平的堆栈面板.可能更多,取决于您从中获取示例的上下文.)由于宽度不受限制,TextBox
不知道应该何时开始换行,并且所以它永远不会换行,即使你启用了换行.您需要做两件事:限制其宽度并启用环绕.
Fundamentally, the problem is this: text wrapping only does anything when an element's width is constrained, but your TextBox
has unconstrained width because it's a descendant of a horizontal StackPanel
. (Well, two horizontal stack panels. Possibly more, depending on the context from which you took your example.) Since the width is unconstrained, the TextBox
has no idea when it is supposed to start wrapping, and so it will never wrap, even if you enable wrapping. You need to do two things: constrain its width and enable wrapping.
这里有更详细的解释.
您的示例包含许多与问题无关的细节.这是我稍微精简的版本,以便更容易解释问题所在:
Your example contains a lot of detail irrelevant to the problem. Here's a version I've trimmed down somewhat to make it easier to explain what's wrong:
<StackPanel Orientation="Horizontal">
<TextBlock Name="DataGridTitle" />
<StackPanel
Margin="5,0"
Orientation="Horizontal"
>
<TextBlock />
<TextBox
Name="VerticallyExpandMe"
Margin="10,2,10,-1"
AcceptsReturn="True"
VerticalAlignment="Center"
Text="{Binding QueryString}"
>
</TextBox>
</StackPanel>
</StackPanel>
所以我已经删除了你包含的 DockPanel
和两个嵌套的 Border
元素,因为它们既不是问题的一部分,也与解决方案无关.因此,我从示例中的一对嵌套 StackPanel
元素开始.而且我还删除了大部分属性,因为它们中的大多数也与布局无关.
So I've removed your containing DockPanel
and the two nested Border
elements inside of that, because they're neither part of the problem nor relevant to the solution. So I'm starting at the pair of nested StackPanel
elements in your example. And I've also removed most of the attributes because most of them are also not relevant to the layout.
这看起来有点奇怪 - 像这样有两个嵌套的水平堆栈面板看起来是多余的,但如果您需要在运行时使嵌套的面板可见或不可见,它在您的原始文件中确实有意义.但是这样更容易看到问题.
This looks a bit weird - having two nested horizontal stack panels like this looks redundant, but it does actually make sense in your original if you need to make the nested one visible or invisible at runtime. But it makes it easier to see the problem.
(空的 TextBlock
标签也很奇怪,但它与原始标签中的完全一样.这似乎没有任何用处.)
(The empty TextBlock
tag is also weird, but that's exactly as it appears in your original. That doesn't appear to be doing anything useful.)
问题是:您的 TextBox
位于一些水平的 StackPanel
元素内,这意味着它的宽度不受限制 - 您无意中告诉文本框它可以自由增长任意宽度,无论实际可用空间有多少.
And here's the problem: your TextBox
is inside some horizontal StackPanel
elements, meaning its width is unconstrained - you have inadvertently told the text box that it is free to grow to any width, regardless of how much space is actually available.
A StackPanel
将始终执行在堆叠方向上不受约束的布局.因此,在布局 TextBox
时,它会将 double.PositiveInfinity
的水平尺寸传递给 TextBox
.所以 TextBox
总是认为它有比它需要的更多的空间.此外,当 StackPanel
的子级请求比实际可用空间更多的空间时,StackPanel
会撒谎,并假装给它足够的空间,但随后将其裁剪.
A StackPanel
will always perform layout that is unconstrained in the direction of stacking. So when it comes to lay out that TextBox
, it'll pass in a horizontal size of double.PositiveInfinity
to the TextBox
. So the TextBox
will always think it has more space than it needs. Moreover, when a child of a StackPanel
asks for more space than is actually available, the StackPanel
lies, and pretends to give it that much space, but then crops it.
(这是您为 StackPanel
的极端简单性所付出的代价 - 它很简单,以至于令人头疼,因为它会很高兴地构建实际上并不适合的布局.您应该仅当您确实由于位于 ScrollViewer
内而确实拥有无限空间时才使用 StackPanel
,或者您确定您不会使用的项目数量足够少空间不足,或者如果您不关心面板末端的项目在它们变得太大时从面板末端溢出,并且您不希望布局系统尝试做任何比简单裁剪内容更聪明的事情.)
(This is the price you pay for the extreme simplicity of StackPanel
- it's simple to the point of being bone-headed, because it will happily construct layouts that don't actually fit. You should only use StackPanel
if either you really do have unlimited space because you're inside a ScrollViewer
, or you are certain that you have sufficiently few items that you're not going to run out of space, or if you don't care about items running off the end of the panel when they get too large and you don't want the layout system to try to do anything more clever than simply cropping the content.)
因此在此处启用文本换行无济于事,因为 StackPanel
将始终假装文本有足够的空间.
So turning on text wrapping won't help here, because the StackPanel
will always pretend that there's more than enough space for the text.
您需要不同的布局结构.使用堆栈面板是错误的,因为它们不会强加您需要让文本换行启动的布局约束.
You need a different layout structure. Stack panels are the wrong thing to use because they will not impose the layout constraint you need to get text wrapping to kick in.
这是一个简单的例子,大致可以满足您的需求:
Here's a simple example that does roughly what you want:
<Grid VerticalAlignment="Top">
<DockPanel>
<TextBlock
x:Name="DataGridTitle"
VerticalAlignment="Top"
DockPanel.Dock="Left"
/>
<TextBox
Name="VerticallyExpandMe"
AcceptsReturn="True"
TextWrapping="Wrap"
Text="{Binding QueryString}"
>
</TextBox>
</DockPanel>
</Grid>
如果您创建一个全新的 WPF 应用程序并将其粘贴为主窗口的内容,您应该会发现它可以满足您的需求 - TextBox
从一行开始,填充可用的宽度,如果您输入文本,它会随着您添加更多文本而一次增加一行.
If you create a brand new WPF application and paste that in as the content of the main window, you should find it does what you want - the TextBox
starts out one line tall, fills the available width, and if you type text in, it'll grow one line at a time as you add more text.
当然,布局行为总是对上下文敏感,因此仅将其放入现有应用程序的中间可能还不够.如果粘贴到固定大小的空间(例如作为窗口的主体),这将起作用,但如果将其粘贴到宽度不受限制的上下文中,则无法正常工作.(例如,在 ScrollViewer
内,或在水平 StackPanel
内.)
Of course, layout behaviour is always sensitive to context, so it may not be enough to just throw that into the middle of your existing application. That will work if pasted into a fixed-size space (e.g. as the body of a window), but will not work correctly if you paste it into a context where width is unconstrained. (E.g., inside a ScrollViewer
, or inside a horizontal StackPanel
.)
因此,如果这对您不起作用,那将是因为布局中其他地方的其他问题 - 其他地方可能还有更多 StackPanel
元素.从您的示例的外观来看,可能值得花一些时间考虑一下您在布局中真正需要什么并对其进行简化 - 负边距的存在,以及似乎没有做任何类似空 TextBlock<的元素/code> 通常表示布局过于复杂.布局中不必要的复杂性使得实现您想要的效果变得非常困难.
So if this doesn't work for you, it'll be because of other things wrong elsewhere in your layout - possibly yet more StackPanel
elements elsewhere. From the look of your example, it's probably worth spending some time thinking about what you really need in your layout and simplifying it - the presence of negative margins, and elements that don't appear to do anything like that empty TextBlock
are usually indicative of an over-complicated layout. And unnecessary complexity in a layout makes it much hard to achieve the effects you're looking for.
这篇关于当文本不再适合一行时,如何将 TextBox 控件配置为自动垂直调整自身大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!