Как сделать верхнюю часть пульта RadioButton Bullet?

У меня есть многострочный переключатель, и я хочу, чтобы пуля была слева от содержимого (по умолчанию), выровненного в верхней части элемента управления радиокнопками. Какой самый простой способ сделать это в XAML?

Ответ 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 &lt;" 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 (a Label не работает)

  • 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>

И как это выглядит:

enter image description here

Единственное, что мне действительно не нравится, - это отрицательное верхнее поле для 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>