Как обернуть OffContent/OnContent ToggleSwitch в UWP?

OffContent/OnContent в пользовательском тумблере не помещается в одну строку, потому что он имеет собственный текст, а ячейка в сетке (где находится ToggleSwitch) недостаточно широка.

Off/OnContent выходит за границы элемента ToggleSwitch, даже когда я определяю пользовательские шаблоны для OffContentTemplate и OnContentTemplate

Пример проблемы

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

Желаемые результаты, где Off/OnContent упакован


person Community    schedule 13.12.2019    source источник


Ответы (2)


В стиле ToggleSwitch OffContentPresenter и OnContentPresenter представляют OffContent и OnContent, вы можете добавить TextWrapping для переноса содержимого и установить ширину, чтобы ограничить его ширину. Что касается полного стиля, вы можете перейти к 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>

Или вы также можете поместить TextBlock в свойства OnContent и OffContent ToggleSwitch, чтобы добиться этого.

<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" />
person Faywang - MSFT    schedule 16.12.2019
comment
Оба примера основаны на [Width=100]. Он не переносит Off/OnContent в нужном месте, а имеет жестко запрограммированную ширину 100. Сообщение содержит пример проблемы. Размер Off/OnContent намного превышает размер ToggleSwitch, поэтому он не упаковывается. Если бы я использовал жестко закодированное значение 100, я мог бы так же легко использовать его в пользовательском шаблоне данных с TextBlock в исходном сообщении. - person ; 07.01.2020
comment
Ширина 0-го столбца уже установлена ​​на 200. Если вы посмотрите на пример выше, ширина элемента ToggleSwitch уже находится в пределах ширины столбца сетки. Off/On Content выходит за пределы ToggleSwitch и Grid. - person ; 13.01.2020

Я сделал все, что предложил Файванг, но безрезультатно. Я заметил, когда я устанавливаю 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. Но ширина TextBlock OffContent — «Auto (246.224)». Как и в моем примере, где он простирается далеко за пределы родительского элемента. В результате он не будет обернут, как ожидалось.

На мой взгляд, это ошибка в поведении ToggleSwitch. Предполагается, что ToggleSwitch упорядочивает расположение своих дочерних элементов. Скажем, если ширина элемента ToggleSwitch равна 200, укажите 40 для Toggle и 160 для OffContent/OnContent. Это всего лишь теория того, как это реализовано, а не реальные цифры. Поскольку OffContent/OnContent почти всегда представляет собой одно короткое слово (либо «Off/On», либо «No/Yes») и не занимает несколько строк, Microsoft никогда не тестировала этот тестовый пример.

person Community    schedule 13.01.2020