【问题标题】:How do I make a RadioButton's Bullet align top?如何使 RadioButton 的 Bullet 对齐顶部?
【发布时间】:2010-10-06 17:35:48
【问题描述】:

我有一个多行单选按钮,我希望项目符号位于内容的左侧(默认情况下),与单选按钮控件的顶部对齐。在 XAML 中执行此操作的最简单方法是什么?

【问题讨论】:

  • 我更新了我的帖子,这似乎有效。

标签: wpf xaml radio-button


【解决方案1】:

注意:请务必查看Rachel's answer - 她将这一阶段进一步纳入通用模板


首先,不要在VerticalAlignmentVerticalContentAlignment(甚至ControlTemplate)上浪费时间。他们不会做你想要或可能期望的事情。

MSDN 中所述,BulletDecorator(CheckBox 和 RadioButton 用于呈现单选/复选按钮的控件)将自动设置图标的位置。您对此没有额外的控制权:

当 Child 出现时,Bullet 始终与文本的第一行对齐 object 是一个文本对象。如果子对象不是文本对象,则 Bullet 与子对象的中心对齐。

除非您更改控制模板(不必要),否则您只能在内容为文本时将单选/复选图标放置在顶部。

因此,如果您执行此类操作,它看起来并不好,因为无论您尝试设置多少 VerticalAlignment 属性,您都无法移动图标。

<RadioButton>
    <StackPanel>
        <TextBlock Text="First line"/>
        <TextBlock Text="Something else"/>
    </StackPanel>
</RadioButton>

但是幸运的是,您可以使用 InlineUIContainerTextBlock 中放入几乎任何您想要的东西。第一行中的文本(或内容)将自动指示图标的位置。如果你想要第一行下面不是文本的内容,只需使用&lt;Linebreak/&gt;,然后使用&lt;InlineUIContainer/&gt;

这是一个带有超大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>

【讨论】:

  • 哈哈,我只是注意到我有 VerticalAlignment="Top" 在说过没有必要之后。我想它可能不在这里
  • WPF RadioButton 的默认样式不再使用 Windows 8 (aero2) 中的 BulletDecorator。它似乎不需要这个 hack,你可以添加一个 Grid。在 Windows XP (luna) 上你仍然需要这个 hack。也许 Windows 7 (aero) 与 Windows 8 相同,但我目前无法检查。
  • @Zodman 很有趣。当我回答这个问题时,我肯定是在使用 Windows 7,所以我认为它一定只是 Windows 8。但是我对你所说的仍然有点怀疑。我不确定“只需添加一个网格”是什么意思 - 它如何知道将复选框与什么相关的中心。您(或其他有空闲时间的人)能否通过屏幕截图详细说明您自己的附加答案。
  • 从内存中,Windows 8 版本自动对齐到顶部(您所追求的行为)。我想我想说的是,您可以使用 Grid(或 StackPanel)垂直布置 RadioButtons,您不需要做任何其他事情(即使 RadioButton 的内容超过多行) .请注意,那是一年多以前的事了;我当然建议任何尝试在 Windows 8 上进行此操作的人重新调查。
【解决方案2】:

我已经基于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 的第一行对齐(@9​​87654326@ 不起作用)

  • 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。这意味着在上面的示例中,用户可以检查所有三个选项,这意味着它不再是单选按钮。
  • @redsolo 您想要从主 RadioButton 传递到模板化 RadioButton 的任何属性都需要像这样添加到模板化 RadioButton 中:GroupName="{TemplateBinding GroupName}"。我没有把它们都加进去,因为代码太多了,但那一个肯定很重要 :)
  • 似乎没有必要在ControlTemplate 中将Margin={TemplateBinding Margin} 添加到RadioButton。此外,如果我这样做,我添加到模板消费者的任何边距似乎都会应用两次。这是你所期望的吗?
  • @dlf 啊,我明白了,很高兴知道。我刚刚使用 Snoop 进行快速测试,发现两个 RadioButton 仍然存在于 UI 树中,并且都设置了 Margin 属性,这就是为什么您看到的边距翻倍。在这种特定情况下,您不需要继承 ControlTemplate 中的 Margin 属性,并且应该只应用一次。
【解决方案3】:

覆盖 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>

【讨论】:

  • 我希望在不需要覆盖单选按钮模板的情况下这样做,因为对齐是我想要更改的唯一内容。
  • 您希望单选按钮位于文本顶部,还是希望单选按钮与按钮并排排列在行顶部(如段落旁边) )?
  • 我也想为 CheckBoxes 做这件事,它应该有相同的解决方案。
  • 我不知道有任何属性可以让您进行这些设计。我会为此使用模板。不过我会做一些窥探(blois.us/Snoop
  • 非常感谢,您的回答与 Multibinding 和 StringFormat 相结合,得到了我所需要的。
猜你喜欢
  • 2016-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-17
  • 2015-04-23
  • 2022-08-23
  • 1970-01-01
相关资源
最近更新 更多