У меня есть многострочный переключатель, и я хочу, чтобы пуля была слева от содержимого (по умолчанию), выровненного в верхней части элемента управления радиокнопками. Какой самый простой способ сделать это в XAML?
Как сделать верхнюю часть пульта RadioButton Bullet?
Ответ 1
Примечание. Обязательно просмотрите ответ Рэйчел - она переходит на один этап в общий шаблон
Прежде всего, не тратьте время на VerticalAlignment
или VerticalContentAlignment
(или даже ControlTemplate
). Они не собираются делать то, что вы хотите или можете ожидать.
Как описано в MSDN a BulletDecorator
(который является элементом управления, который CheckBox и RadioButton использует для рендеринга кнопки радио/проверки ) автоматически установит положение значка. У вас нет дополнительного контроля над этим:
A Bullet всегда выравнивается с первой строкой текста, когда Child object - текстовый объект. Если объект Child не является текстовым объектом, Bullet выравнивается по центру объекта Child.
Если вы не измените шаблон управления (необязательно), вы сможете расположить значок радио/чека вверху, если контент является текстом.
Итак, если вы сделаете что-то подобное, это не будет выглядеть хорошо, потому что вы не сможете переместить значок независимо от того, сколько свойств VerticalAlignment
вы пытаетесь установить.
<RadioButton>
<StackPanel>
<TextBlock Text="First line"/>
<TextBlock Text="Something else"/>
</StackPanel>
</RadioButton>
НО, к счастью, вы можете вместить все, что угодно, в TextBlock
с помощью 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>
Ответ 2
Я построил относительно общий шаблон на основе ответа Саймона Уивера, который можно использовать в большинстве ситуаций, не забывая постоянно настраивать 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
существует, потому что по умолчанию пуля RadioButton выравнивается с первой строкой Text, если содержимое является объектом 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
с целью упрощения его хранения.
Ответ 3
Переопределите Control.Template для RadioButton. Ниже приведен пример из MSDN Пример шаблона управления радиокнопкой
Если вы не хотите переопределять Control.Template для переключателя, вы можете сделать контент a Wrapped TextBlock. см. этот образец
<RadioButton Name="radioButton1">
<TextBlock TextWrapping="Wrap">Here is some multiline text that does some wrapping</TextBlock>
</RadioButton>