我有一个多行单选按钮,我希望项目符号位于内容的左侧(默认情况下),与单选按钮控件的顶部对齐。在 XAML 中执行此操作的最简单方法是什么?
3 回答
注意:请务必查看Rachel 的答案- 她将这一阶段进一步纳入通用模板
首先,不要在VerticalAlignment
or VerticalContentAlignment
(甚至ControlTemplate
)上浪费时间。他们不会做你想要或可能期望的事情。
如MSDN中所述, a BulletDecorator
(CheckBox 和 RadioButton 用于呈现单选/复选按钮的控件)将自动设置图标的位置。您对此没有额外的控制权:
当子对象是文本对象时,项目符号始终与第一行文本对齐。如果子对象不是文本对象,则项目符号将与子对象的中心对齐。
除非您更改控制模板(不必要),否则您只能在内容为文本时将单选/复选图标放置在顶部。
因此,如果您执行此类操作,它看起来不会很好,因为无论VerticalAlignment
您尝试设置多少属性,您都无法移动图标。
<RadioButton>
<StackPanel>
<TextBlock Text="First line"/>
<TextBlock Text="Something else"/>
</StackPanel>
</RadioButton>
但TextBlock
幸运的是,您可以在using中放置几乎任何您想要的东西InlineUIContainer
。第一行中的文本(或内容)将自动指示图标的位置。如果你想要第一行下面的东西不是文本,只需使用<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 的回答构建了一个相对通用的模板,可以在大多数情况下使用,而无需记住一直自定义您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 的第一行对齐(aLabel
不起作用)就是将
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。
此外,如果您想从原始 继承其他属性,例如边距、填充、对齐等,您可能需要在模板中添加一些。我只是TemplateBindings
为了保持简单而绑定。RadioButton
RadioButton
IsChecked
覆盖 RadioButton 的 Control.Template。这是来自 MSDN单选按钮控件模板示例的示例
如果您不想覆盖单选按钮的 Control.Template,您可以将内容设置为 Wrapped TextBlock。看到这个样本
<RadioButton Name="radioButton1">
<TextBlock TextWrapping="Wrap">Here is some multiline text that does some wrapping</TextBlock>
</RadioButton>