imd*_*man 3 c# wpf xaml .net-4.0 controltemplate
我正在尝试简化一些代码并提高可维护性.
我最初正在寻找一种方法,让文本框与左边对齐,可以缩小并扩展到最大值,而不会在达到最大值后在网格单元内居中.
所以我开始写这样的代码......
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<TextBox Text="Some text"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="10"
MaxWidth="150" />
</Grid>
Run Code Online (Sandbox Code Playgroud)
(代码清单1)
这会产生类似这样的东西......

(图1)
如您所见,这将TextBox的最大宽度居中,但它在网格单元的中心对齐.
那么我可能,如果我改变了文本框的水平对齐方式,那么...
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<TextBox Text="Some text"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10"
MaxWidth="100" />
</Grid>
Run Code Online (Sandbox Code Playgroud)
(代码清单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>
Run Code Online (Sandbox Code Playgroud)
(代码3)
这产生了这个......

(图3)
如您所见,嵌套网格填充整个200宽的空间,但文本框填充左侧100,并留下右侧的空白区域.(如果此窗口具有可调整大小,则会缩小并适当扩展)
我想将代码清单3的方法应用于样式或控件模板,因此我可以将其应用于适用于此情况的TextBoxes.
在一个完美的场景中,我会做...
<TextBox Text="Some text"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="10"
MaxWidth="100"
Style="{StaticResource ExpandingTextBox}" />
Run Code Online (Sandbox Code Playgroud)
(代码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>
Run Code Online (Sandbox Code Playgroud)
(代码5)
但这只会导致文本框从我的表单中消失.我不是很擅长写这样的模板,所以我有点不知所措.
另外,我刚刚意识到的一件事是嵌套列的宽度= MaxWidth + 2 x Margin.我不介意在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>
Run Code Online (Sandbox Code Playgroud)
这应该工作,但imo,有点奇怪..
感谢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>
Run Code Online (Sandbox Code Playgroud)
(代码清单6)
当然,将其应用到我的页面的 XAML 标记中,如下所示......
<TextBox Grid.Column="1"
Grid.Row="3"
Text="{Binding Path=Username}"
Style="{StaticResource ExpandingTextBox}"
Margin="10"
MaxWidth="200" />
Run Code Online (Sandbox Code Playgroud)
(代码清单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>
Run Code Online (Sandbox Code Playgroud)
(代码清单8)
在 XAML 中的应用是这样的......
<TextBox Grid.Column="1"
Grid.Row="3"
Text="{Binding Path=Username}"
Style="{StaticResource ExpandingTextBoxMaxWidthInTag}"
Margin="10"
Tag="200" />
Run Code Online (Sandbox Code Playgroud)
最后给出了这样的期望结果......

(图5)

(图6)
因此,真正的技巧是意识到我不一定要限制整个模板化控件的最大宽度,而只是想限制控件内部 TextBox 的宽度!
一旦我弄清楚了这一点,只有使用 Tag 属性才有意义,它对根级别的控件没有任何作用!
我希望这可以帮助其他可能遇到此问题的人!
| 归档时间: |
|
| 查看次数: |
13863 次 |
| 最近记录: |