【问题标题】:How to wrap OffContent/OnContent of a ToggleSwitch in UWP?如何在 UWP 中包装 ToggleSwitch 的 OffContent/OnContent?
【发布时间】:2020-01-14 03:12:55
【问题描述】:

自定义切换开关中的 OffContent/OnContent 不适合一行,因为它有自定义文本,并且网格中的单元格(放置 ToggleSwitch 的位置)不够宽。

即使我为 OffContentTemplate 和 OnContentTemplate 定义自定义模板,Off/OnContent 也会超出 ToggleSwitch 元素的边界

Problem example

<DataTemplate x:Key="ToggleSwitchTextBlockTemplate">
    <TextBlock
        TextWrapping="Wrap"
        Text="{Binding}"
        HorizontalAlignment="Stretch" />
</DataTemplate>

<ToggleSwitch
    Grid.Row="2"
    Grid.Column="0"
    x:Name="SomeToggle"
    Header="Some header"
    OffContent="Off content to verify if string is wrapped"
    OnContent="On content to verify if string is wrapped"
    OffContentTemplate="{StaticResource ToggleSwitchTextBlockTemplate}"
    OnContentTemplate="{StaticResource ToggleSwitchTextBlockTemplate}"
    Width="200" />

如何强制 Off/OnContent 换行并适合 ToggleSwitch 边界?

Desired results, where Off/OnContent is wrapped

【问题讨论】:

    标签: uwp uwp-xaml toggleswitch


    【解决方案1】:

    在ToggleSwitch 的样式中,有OffContentPresenter 和OnContentPresenter 分别代表OffContent 和OnContent,可以添加TextWrapping 来包裹内容并设置Width 来限制其宽度。关于完整的样式,可以去generic.xaml复制一下。

    .xaml:

           <Style x:Key="ToggleSwitchStyle1" TargetType="ToggleSwitch">
                ......
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ToggleSwitch">
                            <Grid Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{TemplateBinding CornerRadius}">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <VisualStateManager.VisualStateGroups>
                                    ......
                                </VisualStateManager.VisualStateGroups>
                                <ContentPresenter x:Name="HeaderContentPresenter" AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Foreground="{ThemeResource ToggleSwitchHeaderForeground}" IsHitTestVisible="False" Margin="{ThemeResource ToggleSwitchTopHeaderMargin}" Grid.Row="0" TextWrapping="Wrap" VerticalAlignment="Top" Visibility="Collapsed" x:DeferLoadStrategy="Lazy"/>
                                <Grid HorizontalAlignment="Left" MinWidth="{StaticResource ToggleSwitchThemeMinWidth}" Grid.Row="1" VerticalAlignment="Top">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition MaxWidth="12" Width="12"/>
                                        <ColumnDefinition Width="Auto"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="{ThemeResource ToggleSwitchPreContentMargin}"/>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="{ThemeResource ToggleSwitchPostContentMargin}"/>
                                    </Grid.RowDefinitions>
                                    <Grid x:Name="SwitchAreaGrid" Background="{ThemeResource ToggleSwitchContainerBackground}" Grid.ColumnSpan="3" Control.IsTemplateFocusTarget="True" Margin="0,5" Grid.RowSpan="3"/>
                                    <ContentPresenter TextWrapping="Wrap" Width="100" x:Name="OffContentPresenter" AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding OffContentTemplate}" Content="{TemplateBinding OffContent}" Grid.Column="2" Foreground="{TemplateBinding Foreground}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="False" Opacity="0" Grid.RowSpan="3" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                    <ContentPresenter TextWrapping="Wrap" Width="100" x:Name="OnContentPresenter" AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding OnContentTemplate}" Content="{TemplateBinding OnContent}" Grid.Column="2" Foreground="{TemplateBinding Foreground}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="False" Opacity="0" Grid.RowSpan="3" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                    ......
    
                                </Grid>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    

    或者你也可以在ToggleSwitch的OnContent和OffContent属性中放一个TextBlock来实现。

    <ToggleSwitch Width="200" Grid.Row="2" Grid.Column="0" x:Name="SomeToggle" 
                  Header="Some header" >
        <ToggleSwitch.OffContent>
            <TextBlock Width="100" TextWrapping="Wrap">Off content to verify if string is wrapped</TextBlock>
        </ToggleSwitch.OffContent>
    </ToggleSwitch>
    

    更新:

    如果您不想直接设置 Width 来限制其宽度,您可以将 ColumnDefinition 从“Auto”更改为“*”。 “自动”意味着一列的宽度与其内的元素一样多。但是“*”是基于剩余空间的宽度。所以当你将 ColumnDefinition 设置为“ * ”时,它会根据剩余的空间来放置你的文本,如果不够就会换行。

    需要修改的样式部分是(你只需要从原来的样式更改以下部分):

    <Grid HorizontalAlignment="Left" MinWidth="{StaticResource ToggleSwitchThemeMinWidth}" Grid.Row="1" VerticalAlignment="Top">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition MaxWidth="12" Width="12"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        ......
    </Grid>
    

    用法:

    <ToggleSwitch
        Grid.Row="2"
        Grid.Column="0"
        x:Name="SomeToggle"
        Header="Some header"
        OffContent="Off content to verify if string is wrapped"
        OnContent="On content to verify if string is wrapped"
        OffContentTemplate="{StaticResource ToggleSwitchTextBlockTemplate}"
        OnContentTemplate="{StaticResource ToggleSwitchTextBlockTemplate}"
        Style="{StaticResource ToggleSwitchStyle1}"
        Width="200" />
    

    【讨论】:

    • 这两个例子都依赖于 [Width="100"]。它不会将 Off/OnContent 包装在正确的位置,而是以硬编码的 100 宽度包装。帖子有一个problem example。 Off/OnContent 的大小超出了 ToggleSwitch 大小,这就是它没有被包装的原因。如果我使用硬编码的 100 值,我可以在原始帖子中使用 TextBlock 的自定义 DataTemplate 轻松使用。
    • 第 0 列的宽度已经设置为 200。如果您查看上面的示例,宽度 ToggleSwitch 元素已经在 Grid 的列宽范围内。 Off/On 内容超出了 ToggleSwitch 和 Grid 的边界。
    【解决方案2】:

    我做了所有Faywang的建议,但没有任何结果。 我注意到,当我直接设置 OffContent(而不是定义模板)并检查元素的属性时

            <ToggleSwitch
                Grid.Row="2"
                Grid.Column="0"
                x:Name="SomeToggle"
                Header="Some header"
                HeaderTemplate="{StaticResource ToggleSwitchTextBlockTemplate}"
                OnContent="On content to verify if string is wrapped"
                OnContentTemplate="{StaticResource ToggleSwitchTextBlockTemplate}"
                Width="200">
                <ToggleSwitch.OffContent>
                    <TextBlock
                        Width="Auto"
                        TextWrapping="Wrap"
                        Text="Off content to verify if string is wrapped" />
                </ToggleSwitch.OffContent>
            </ToggleSwitch>
    

    ToggleSwitch 的宽度是 200。但是 OffContent 的 TextBlock 的宽度是“Auto (246.224)”。就像在我的示例中,它远远超出了父元素。因此它不会按预期换行。

    我对此的看法,这是 ToggleSwitch 行为中的一个错误。 ToggleSwitch 应该安排其子项的布局。假设,如果 ToggleSwitch 元素的 Width 为 200,则将 40 分配给 Toggle,将 160 分配给 OffContent/OnContent。这只是关于如何实施的理论,而不是实际数字。 由于 OffContent/OnContent 几乎总是一个简短的词(“Off/On”或“No/Yes”)并且不跨越多行,因此 Microsoft 从未测试过这个测试用例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 2018-06-28
      • 1970-01-01
      • 2017-03-03
      相关资源
      最近更新 更多