【发布时间】:2010-10-06 17:35:48
【问题描述】:
我有一个多行单选按钮,我希望项目符号位于内容的左侧(默认情况下),与单选按钮控件的顶部对齐。在 XAML 中执行此操作的最简单方法是什么?
【问题讨论】:
-
我更新了我的帖子,这似乎有效。
标签: wpf xaml radio-button
我有一个多行单选按钮,我希望项目符号位于内容的左侧(默认情况下),与单选按钮控件的顶部对齐。在 XAML 中执行此操作的最简单方法是什么?
【问题讨论】:
标签: wpf xaml radio-button
注意:请务必查看Rachel's answer - 她将这一阶段进一步纳入通用模板
首先,不要在VerticalAlignment 或VerticalContentAlignment(甚至ControlTemplate)上浪费时间。他们不会做你想要或可能期望的事情。
如MSDN 中所述,BulletDecorator(CheckBox 和 RadioButton 用于呈现单选/复选按钮的控件)将自动设置图标的位置。您对此没有额外的控制权:
当 Child 出现时,Bullet 始终与文本的第一行对齐 object 是一个文本对象。如果子对象不是文本对象,则 Bullet 与子对象的中心对齐。
除非您更改控制模板(不必要),否则您只能在内容为文本时将单选/复选图标放置在顶部。
因此,如果您执行此类操作,它看起来并不好,因为无论您尝试设置多少 VerticalAlignment 属性,您都无法移动图标。
<RadioButton>
<StackPanel>
<TextBlock Text="First line"/>
<TextBlock Text="Something else"/>
</StackPanel>
</RadioButton>
但是幸运的是,您可以使用 InlineUIContainer 在 TextBlock 中放入几乎任何您想要的东西。第一行中的文本(或内容)将自动指示图标的位置。如果你想要第一行下面不是文本的内容,只需使用<Linebreak/>,然后使用<InlineUIContainer/>
这是一个带有超大TextBox 的示例,以更清楚地显示正在发生的事情。
<RadioButton>
<TextBlock VerticalAlignment="Top" TextWrapping="Wrap">
<TextBlock Text="Products with <" VerticalAlignment="Center" Margin="0,0,5,0"/>
<InlineUIContainer BaselineAlignment="Center">
<TextBox FontSize="30" Width="25" Text="10" Margin="0,0,5,0"/>
</InlineUIContainer>
<TextBlock VerticalAlignment="Center" Margin="0,0,5,0">
<Run Text="days" FontWeight="Bold"/>
<Run Text="inventory" />
</TextBlock>
<LineBreak/>
<InlineUIContainer>
<StackPanel>
<CheckBox Content="Include unsold products" />
<CheckBox Content="Include something else" />
</StackPanel>
</InlineUIContainer>
</TextBlock>
</RadioButton>
【讨论】:
我已经基于Simon Weaver's answer 构建了一个相对通用的模板,可以在大多数情况下使用,而无需记住一直自定义您的RadioButton.Content。
<ControlTemplate x:Key="MultiLineRadioButtonTemplate" TargetType="{x:Type RadioButton}">
<RadioButton IsChecked="{TemplateBinding IsChecked}">
<TextBlock>
<LineBreak />
<InlineUIContainer>
<ContentPresenter Margin="0,-21,0,8"
Content="{TemplateBinding ContentPresenter.Content}"
ContentTemplate="{TemplateBinding ContentPresenter.ContentTemplate}"/>
</InlineUIContainer>
</TextBlock>
</RadioButton>
</ControlTemplate>
解释模板的工作原理:
TextBlock 存在是因为默认情况下,如果内容是 Text 对象,RadioButton 项目符号会与 Text 的第一行对齐(@987654326@ 不起作用)
LineBreak是将内容换行,所以创建第一行
InlineUIContainer 是我们可以将非文本内容放入TextBlock
ContentPresenter 是保存实际内容,它有一个负的上边距来去除LineBreak 对象留下的空间。
以下是一些示例内容:
<StackPanel>
<RadioButton Template="{StaticResource MultiLineRadioButtonTemplate}">
<StackPanel>
<Label Content="Option 1" />
<StackPanel>
<CheckBox Content="Some setting" />
<CheckBox Content="Some other setting" />
</StackPanel>
</StackPanel>
</RadioButton>
<RadioButton Template="{StaticResource MultiLineRadioButtonTemplate}">
<StackPanel>
<Label Content="Option 2" />
<DataGrid AutoGenerateColumns="False" Height="100">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" />
<DataGridTextColumn Header="Date" />
<DataGridTextColumn Header="Total" />
<DataGridTextColumn Header="Count" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</RadioButton>
<RadioButton Template="{StaticResource MultiLineRadioButtonTemplate}">
<StackPanel>
<Label Content="Option 3" />
<TextBlock TextWrapping="WrapWithOverflow" Margin="2">
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</TextBlock>
</StackPanel>
</RadioButton>
</StackPanel>
以及它的外观:
我真正不满意的唯一一点是ContentPresenter 被硬编码的负上边距,因为如果您更改字体大小,则必须手动调整该边距。
为计算换行符高度的Margin 属性构建一个转换器({TemplateBinding FontSize}?)可能并不难,甚至是具有此行为的 RadioButton 控件的扩展版本默认,但现在我可以根据我的应用程序的默认字体大小硬编码 -21。
另外,如果您想从原始RadioButton 继承其他属性,例如边距、填充、对齐等,您可能需要在模板中的RadioButton 中添加一些TemplateBindings。我只绑定到IsChecked 保持简单的目的。
【讨论】:
GroupName="{TemplateBinding GroupName}"。我没有把它们都加进去,因为代码太多了,但那一个肯定很重要 :)
ControlTemplate 中将Margin={TemplateBinding Margin} 添加到RadioButton。此外,如果我这样做,我添加到模板消费者的任何边距似乎都会应用两次。这是你所期望的吗?
覆盖 RadioButton 的 Control.Template。这是来自 MSDN Radio Button Control Template Example的示例
如果您不想覆盖单选按钮的 Control.Template,您可以将内容设置为 Wrapped TextBlock。看这个样本
<RadioButton Name="radioButton1">
<TextBlock TextWrapping="Wrap">Here is some multiline text that does some wrapping</TextBlock>
</RadioButton>
【讨论】: