wpf 如何应用 TextBox 控件模板?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16222421/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to apply TextBox Control Template?
提问by imdandman
I'm trying to simplify some code and improve my maintainability.
我正在尝试简化一些代码并提高我的可维护性。
I was initially seeking a way to have a text box aligned to the left, that can shrink and expand to a maximum value without centering inside a grid cell after reaching the maximum value.
我最初是在寻找一种方法,使文本框与左侧对齐,在达到最大值后,它可以缩小和扩展到最大值,而无需在网格单元内居中。
So I started out writing some code like this...
所以我开始写一些这样的代码......
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<TextBox Text="Some text"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="10"
MaxWidth="150" />
</Grid>
(Code Listing 1)
(代码清单 1)
And that yields something looking like this...
这会产生看起来像这样的东西......


(Figure 1)
(图1)
As you can see, this centers the TextBox with it's max width, but it is aligned in the center of the grid cell.
如您所见,这将 TextBox 以其最大宽度居中,但它与网格单元格的中心对齐。
So then I though maybe if i changed the horizontal alignment of the text box like so...
那么我虽然也许如果我像这样改变文本框的水平对齐方式......
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<TextBox Text="Some text"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10"
MaxWidth="100" />
</Grid>
(Code Listing 2)
(代码清单 2)
But unfortunately, that only yields something looking like this...
但不幸的是,这只产生了看起来像这样的东西......


(Figure 2)
(图2)
Again, this isn't right because, despite all the empty space on the right, the text box is not expanding to its max width of 100 like I want.
同样,这是不对的,因为尽管右侧有所有空白区域,但文本框并没有像我想要的那样扩展到其最大宽度 100。
Eventually, I found that if put the TextBox inside a nested grid, you will achieve the desired effect.
最终,我发现如果将 TextBox 放在嵌套网格中,您将达到预期的效果。
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"
MaxWidth="120" />
<ColumnDefinition Width="0*" />
</Grid.ColumnDefinitions>
<TextBox Text="Some text"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="10"
MaxWidth="100" />
</Grid>
</Grid>
(Code Listing 3)
(代码清单 3)
Which yields this...
这产生了这个......


(Figure 3)
(图3)
As you can see, the nested grid fills the entire 200 wide space, but the text box fills the left 100, and leaves the empty space on the right. (If this window is re-sizable it will shrink and expand appropriately)
如您所见,嵌套网格填充了整个 200 宽的空间,但文本框填充了左侧的 100,并在右侧留下了空白空间。(如果此窗口可重新调整大小,它将适当缩小和扩展)
I would like to apply the methods of Code Listing 3to a style or control template, so I can blanket apply it to TextBoxes where this situation is applicable.
我想将代码清单 3 中的方法应用于样式或控件模板,以便我可以将其全面应用于这种情况的文本框。
In a perfect scenario, I would do something like...
在完美的情况下,我会做类似的事情......
<TextBox Text="Some text"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="10"
MaxWidth="100"
Style="{StaticResource ExpandingTextBox}" />
(Code Listing 4)
(代码清单 4)
And achieve the same results as Figure 3.
并达到与图3相同的效果。
I tried the following...
我尝试了以下...
<Style TargetType="{x:Type TextBox}"
x:Key="ExpandingTextBox">
<Setter Property="OverridesDefaultStyle"
Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"
MaxWidth="170" />
<ColumnDefinition Width="0*" />
</Grid.ColumnDefinitions>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
(Code Listing 5)
(代码清单 5)
But that just causes the text box to disappear from my form all together. I'm not very good at writing templates like this, so I'm kind of at a loss.
但这只会导致文本框一起从我的表单中消失。我不太擅长写这样的模板,所以我有点不知所措。
Also, one thing I just realized is that the width of the nested column = MaxWidth + 2 x Margin. I wouldn't mind setting the column width explicitly in the TextBox declaration, but if it could be automatic, that would be awesome.
另外,我刚刚意识到的一件事是嵌套列的宽度 = MaxWidth + 2 x Margin。我不介意在 TextBox 声明中明确设置列宽,但如果它可以是自动的,那就太棒了。
回答by jure
You need a TextBox instead of ContentPresenter inside your Template. You replaced default template for TextBox with one that no longer has area for text input. Try like this:
您需要在模板中使用 TextBox 而不是 ContentPresenter。您将 TextBox 的默认模板替换为不再具有文本输入区域的模板。像这样尝试:
<Style TargetType="{x:Type TextBox}" x:Key="ExpandingTextBox">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"
MaxWidth="170" />
<ColumnDefinition Width="0*" />
</Grid.ColumnDefinitions>
<TextBox Text="{TemplateBinding Text}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="10"
MaxWidth="100"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This should work but imo, is a bit wierd..
这应该可以工作,但是imo,有点奇怪..
回答by imdandman
Thanks to jurefor getting me started. As always, it turns out that the solution is a bit more convoluted than it originally lets on.
感谢jure让我开始。与往常一样,结果证明该解决方案比最初提出的要复杂一些。
Let's examine what I did.
让我们检查一下我做了什么。
Using the ideas presented in the previous post, and after a bit of finagling, I came up with the following code.
使用上一篇文章中提出的想法,经过一番折腾,我想出了以下代码。
<Style TargetType="{x:Type TextBox}"
x:Key="ExpandingTextBox">
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*">
<ColumnDefinition.MaxWidth>
<Binding Path="MaxWidth"
RelativeSource="{RelativeSource TemplatedParent}">
</Binding>
</ColumnDefinition.MaxWidth>
</ColumnDefinition>
<ColumnDefinition Width="0*" />
</Grid.ColumnDefinitions>
<TextBox Text="{TemplateBinding Text}">
<TextBox.MaxWidth>
<Binding Path="MaxWidth"
RelativeSource="{RelativeSource TemplatedParent}" />
</TextBox.MaxWidth>
</TextBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
(Code Listing 6)
(代码清单 6)
And of course applied it in the XAML markup for my page like this...
当然,将它应用到我的页面的 XAML 标记中,就像这样......
<TextBox Grid.Column="1"
Grid.Row="3"
Text="{Binding Path=Username}"
Style="{StaticResource ExpandingTextBox}"
Margin="10"
MaxWidth="200" />
(Code Listing 7)
(代码清单 7)
That gives a result like this...
这给出了这样的结果......


(Figure 4)
(图4)
After looking at that image, and thinking for a while, it donned on me that the problem was that even though I was applying the max width inside the style correctly, the max width property was still being applied to the root of the control in XAML.
查看该图像并思考了一段时间后,我发现问题在于即使我正确地在样式中应用了最大宽度,最大宽度属性仍然应用于 XAML 中控件的根.
Essentially it was squeezing it down to the max width on the page, and then after that was done, it applied the max width pursuant to the styling!
本质上它是将其压缩到页面上的最大宽度,然后在完成之后,根据样式应用最大宽度!
So simple, but so elusive!
如此简单,却如此难以捉摸!
Therefore, I modified the style to use the Tag property to apply to the styled max width elements, since the Tag property doesn't do anything at the root.
因此,我修改了样式以使用 Tag 属性来应用于样式化的最大宽度元素,因为 Tag 属性在根部不执行任何操作。
<Style TargetType="{x:Type TextBox}"
x:Key="ExpandingTextBoxMaxWidthInTag">
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*">
<ColumnDefinition.MaxWidth>
<Binding Path="Tag"
RelativeSource="{RelativeSource TemplatedParent}">
</Binding>
</ColumnDefinition.MaxWidth>
</ColumnDefinition>
<ColumnDefinition Width="0*" />
</Grid.ColumnDefinitions>
<TextBox Text="{TemplateBinding Text}">
<TextBox.MaxWidth>
<Binding Path="Tag"
RelativeSource="{RelativeSource TemplatedParent}" />
</TextBox.MaxWidth>
</TextBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
(Code Listing 8)
(代码清单 8)
Which is applied in XAML like this...
像这样在 XAML 中应用...
<TextBox Grid.Column="1"
Grid.Row="3"
Text="{Binding Path=Username}"
Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
Margin="10"
Tag="200" />
And finallygives the desired results like this...
而最后给出了这样的期望的结果...


(Figure 5)
(图5)


(Figure 6)
(图6)
So, the real trick was realizing that I didn't necessarily want to limit the max width of the entire templated control, but instead just wanted to limit the width of the TextBox internal to the control!
所以,真正的技巧是意识到我不一定要限制整个模板化控件的最大宽度,而只是想限制控件内部 TextBox 的宽度!
Once I figured that out, it only made sense to use the Tag property which wasn't doing anything to the control at the root level!
一旦我明白了这一点,只有使用 Tag 属性才有意义,它对根级别的控件没有任何作用!
I hope this helps anyone else who might have this problem!
我希望这可以帮助其他可能遇到此问题的人!

