C# 如何应用文本框控件模板?

C# 如何应用文本框控件模板?,c#,wpf,xaml,.net-4.0,controltemplate,C#,Wpf,Xaml,.net 4.0,Controltemplate,我试图简化一些代码并提高可维护性 我最初是在寻找一种方法,使文本框向左对齐,在达到最大值后,可以收缩和扩展到最大值,而无需在网格单元内居中 所以我开始写一些像这样的代码 <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="200" /> </Grid.ColumnDefinitions> <TextBox Text="Some text"

我试图简化一些代码并提高可维护性

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

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

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBox}"
          Margin="10"
          MaxWidth="200" />
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
          Margin="10"
          Tag="200" />

(代码清单1)

这就产生了这样的结果

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBox}"
          Margin="10"
          MaxWidth="200" />
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
          Margin="10"
          Tag="200" />

(图1)

如您所见,这将使文本框以其最大宽度居中,但它在网格单元的中心对齐

所以我想如果我像这样改变文本框的水平对齐方式

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

(代码清单2)

但不幸的是,这只会产生这样的结果

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBox}"
          Margin="10"
          MaxWidth="200" />
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
          Margin="10"
          Tag="200" />

(图2)

同样,这是不对的,因为尽管右边有所有的空白,文本框并没有像我想要的那样扩展到最大宽度100

最后,我发现如果将文本框放在嵌套的网格中,就会达到预期的效果

<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 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+2x边距。我不介意在TextBox声明中显式设置列宽,但如果可以自动设置,那就太棒了。

模板中需要一个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>

这应该行得通,但我觉得有点奇怪。

感谢你让我开始。和往常一样,结果证明,解决方案比最初允许的要复杂一些

让我们看看我做了什么

利用上一篇文章中提出的想法,经过一番欺骗,我想出了以下代码

<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标记中应用了它,如下所示

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBox}"
          Margin="10"
          MaxWidth="200" />
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
          Margin="10"
          Tag="200" />

(代码清单7)

这样的结果

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBox}"
          Margin="10"
          MaxWidth="200" />
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
          Margin="10"
          Tag="200" />

(图4)

在查看该图像并思考了一会儿之后,我意识到问题在于,即使我在样式中正确应用了max-width,max-width属性仍然应用于XAML中控件的根

从本质上讲,它是压缩到页面上的最大宽度,然后在完成后,它根据样式应用最大宽度

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

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

(代码清单8)

它在XAML中的应用如下

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBox}"
          Margin="10"
          MaxWidth="200" />
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
          Margin="10"
          Tag="200" />

最后给出了这样的预期结果

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>
    <TextBox Text="Some text"
             VerticalAlignment="Center"
             HorizontalAlignment="Stretch"
             Margin="10"
             MaxWidth="150" />
</Grid>
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBox}"
          Margin="10"
          MaxWidth="200" />
<TextBox  Grid.Column="1"
          Grid.Row="3"
          Text="{Binding Path=Username}"
          Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
          Margin="10"
          Tag="200" />

(图5)

(图6)

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

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


我希望这能帮助其他可能有这个问题的人

谢谢你的帮助。用你写的,我知道我到底想要什么