【问题标题】:How to apply TextBox Control Template?如何应用文本框控件模板?
【发布时间】:2013-04-25 18:47:38
【问题描述】:

我正在尝试简化一些代码并提高我的可维护性。

我最初是在寻找一种让文本框向左对齐的方法,该方法可以在达到最大值后收缩和扩展至最大值,而无需在网格单元内居中。

所以我开始写一些这样的代码......

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>

(代码清单 1)

这会产生看起来像这样的东西......

(图一)

如您所见,这会将 TextBox 以其最大宽度居中,但它与网格单元格的中心对齐。

那么我可能会像这样更改文本框的水平对齐方式......

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox  Text="Some text"
              VerticalAlignment="Center"
              HorizontalAlignment="Left"
              Margin="10"
              MaxWidth="100" />
</Grid>

(代码清单 2)

但不幸的是,这只会产生看起来像这样的东西......

(图2)

再一次,这是不对的,因为尽管右侧有所有空白空间,但文本框并没有像我想要的那样扩展到其最大宽度 100。

最后,我发现如果把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>

(代码清单 3)

这会产生这个...

(图3)

如您所见,嵌套网格填充了整个 200 宽的空间,但文本框填充了左侧的 100,并在右侧留下了空白空间。 (如果这个窗口可以调整大小,它会适当地缩小和扩大)

我想将代码清单 3 的方法应用到样式或控件模板,因此我可以将它一揽子应用到适用于这种情况的 TextBox。

在一个完美的场景中,我会做类似...

<TextBox Text="Some text"
         VerticalAlignment="Center"
         HorizontalAlignment="Stretch"
         Margin="10"
         MaxWidth="100"
         Style="{StaticResource ExpandingTextBox}" /> 

(代码清单 4)

并达到与图3相同的结果。

我尝试了以下...

<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>

(代码清单 5)

但这只会导致文本框从我的表单中消失。我不太擅长写这样的模板,所以有点不知所措。

另外,我刚刚意识到的一件事是嵌套列的宽度 = MaxWidth + 2 x Margin。我不介意在 TextBox 声明中明确设置列宽,但如果它可以是自动的,那就太棒了。

【问题讨论】:

    标签: c# wpf xaml .net-4.0 controltemplate


    【解决方案1】:

    您需要在模板中使用 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>
    

    这应该可以,但是 imo 有点奇怪..

    【讨论】:

    • 感谢您的帮助。使用您所写的内容,我确切地弄清楚了我想要做什么并从那里扩展。请参阅下面的答案。
    【解决方案2】:

    感谢 jure 让我开始。与往常一样,事实证明,该解决方案比最初允许的要复杂一些。

    让我们看看我做了什么。

    使用上一篇文章中提出的想法,经过一番摸索,我想出了以下代码。

    <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>
    

    (代码清单 6)

    当然,像这样在我的页面的 XAML 标记中应用它...

    <TextBox  Grid.Column="1"
              Grid.Row="3"
              Text="{Binding Path=Username}"
              Style="{StaticResource ExpandingTextBox}"
              Margin="10"
              MaxWidth="200" />
    

    (代码清单 7)

    这给出了这样的结果......

    (图4)

    看了那张图片,想了一会儿,我发现问题是即使我在样式中正确应用了最大宽度,最大宽度属性仍然被应用到XAML 中的控制。

    本质上它是在页面上将其压缩到最大宽度,然后在完成之后,根据样式应用最大宽度!

    如此简单,却如此难以捉摸!

    因此,我修改了样式以使用 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>
    

    (代码清单 8)

    像这样在 XAML 中应用...

    <TextBox  Grid.Column="1"
              Grid.Row="3"
              Text="{Binding Path=Username}"
              Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
              Margin="10"
              Tag="200" />
    

    终于给出了这样的期望结果...

    (图5)

    (图6)

    所以,真正的诀窍是意识到我不一定要限制整个模板化控件的最大宽度,而只是想限制控件内部 TextBox 的宽度!

    一旦我明白了这一点,使用 Tag 属性才有意义,它对根级别的控件没有任何作用!

    我希望这可以帮助其他可能遇到此问题的人!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多