简体   繁体   English

如何应用TextBox控件模板?

[英]How to apply TextBox Control Template?

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... 这会产生类似这样的东西......

网格居中的TextBox

(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... 但不幸的是,这只会产生这样的东西......

太小的TextBox左对齐

(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... 这产生了这个......

正确看TextBox

(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. 如您所见,嵌套网格填充整个200宽的空间,但文本框填充左侧100,并留下右侧的空白区域。 (If this window is re-sizable it will shrink and expand appropriately) (如果此窗口具有可调整大小,则会缩小并适当扩展)

I would like to apply the methods of Code Listing 3 to a style or control template, so I can blanket apply it to TextBoxes where this situation is applicable. 我想将代码清单3的方法应用于样式或控件模板,因此我可以将其应用于适用于此情况的TextBoxes。

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. 另外,我刚刚意识到的一件事是嵌套列的宽度= 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. 我不介意在TextBox声明中显式设置列宽,但如果它可以是自动的,那将是非常棒的。

You need a TextBox instead of ContentPresenter inside your Template. 您需要在模板中使用TextBox而不是ContentPresenter。 You replaced default template for TextBox with one that no longer has area for text input. 您将TextBox的默认模板替换为不再具有文本输入区域的模板。 Try like this: 试试这样:

 <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,有点奇怪..

Thanks to jure for getting me started. 感谢jure让我开始。 As always, it turns out that the solution is a bit more convoluted than it originally lets on. 与往常一样,事实证明解决方案比最初允许的解决方案更复杂。

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属性应用于样式化的max width元素,因为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 finally gives 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! 我希望这可以帮助其他可能有这个问题的人!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM