Изменение состояний для переключателя в пользовательском стиле с двумя различными синтаксисами разметки путей

#wpf #xaml #controltemplate

Вопрос:

Я новичок в WPF и пытаюсь придумать шаблон пользовательского стиля для a ToggleButton . До сих пор мне удавалось определять пути с помощью кривых Безье, но я застрял в следующей проблеме:

  • Как я могу объединить два Path s, чтобы при наведении курсора ToggleButton цвет в ОБОИХ ПУТЯХ менялся в соответствии с прикрепленным изображением. Должно быть два разных значения цвета, одно для основной части, а другое для синей полосы вверху. Вот часть моего холста в XAML:
 <Canvas Width="180" Height="180" Canvas.Left="0" Canvas.Top="0" HorizontalAlignment="Center" VerticalAlignment="Top">
    <Path Stretch="Fill" StrokeLineJoin="Miter" Stroke="#FFB5BECB" Fill="#FFEDF2F7" Data="F1 M 90,18C 109.882,18 127.882,26.0589 140.912,39.0883L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 90,18 Z"/>
    <Path Stretch="Fill" StrokeLineJoin="Miter" Stroke="#FFB5BECB" Fill="#FFCDD5DE" Data="F1 M 90,18C 109.882,18 127.882,26.0589 140.912,39.0883L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 90,18 Z "/>
    <Path Stretch="Fill" StrokeThickness="1" StrokeLineJoin="Miter" Stroke="#FF6F9FFF" Fill="#FF6F9FFF" Data="F1 M 89.9999,5.00005C 113.472,5.00005 134.722,14.514 150.104,29.896L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 89.9999,5.00005 Z "/>
    <Path Stretch="Fill" StrokeThickness="1" StrokeLineJoin="Miter" Stroke="#FF13487E" Fill="#FF13487E" Data="F1 M 89.9999,5.00005C 113.472,5.00005 134.722,14.514 150.104,29.896L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 89.9999,5.00005 Z"/>
</Canvas>
 

На следующем рисунке показаны ожидаемое основное состояние и состояние наведения.

Изображение, показывающее основное состояние и состояние при наведении.

Ответ №1:

Вы можете назвать свои элементы, присвоив x:Name им . Затем вы можете обратиться к ним в a Trigger , который проверяет IsMouseOver свойство родительского контейнера, например Canvas .

Поскольку вы не предоставляете свой шаблон полного контроля, эта часть, которую вы опубликовали, адаптирована для изменения Stroke s и Fill Path s при наведении курсора мыши.

 <ToggleButton Content="Templated Toggle Button">
   <ToggleButton.Template>
      <ControlTemplate TargetType="{x:Type ToggleButton}">
         <!-- ...here might be a container that you did not provide in your question. -->
         <Canvas x:Name="MyCanvas"  Width="180" Height="180" Canvas.Left="0" Canvas.Top="0" HorizontalAlignment="Center" VerticalAlignment="Top">
            <Path x:Name="TopPart" Stretch="Fill" StrokeLineJoin="Miter" Stroke="#FFB5BECB" Fill="#FFCDD5DE" Data="F1 M 90,18C 109.882,18 127.882,26.0589 140.912,39.0883L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 90,18 Z "/>
            <Path x:Name="BottomPart" Stretch="Fill" StrokeThickness="1" StrokeLineJoin="Miter" Stroke="#FF13487E" Fill="#FF13487E" Data="F1 M 89.9999,5.00005C 113.472,5.00005 134.722,14.514 150.104,29.896L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 89.9999,5.00005 Z"/>
         </Canvas>
         <ControlTemplate.Triggers>
            <Trigger SourceName="MyCanvas" Property="IsMouseOver" Value="True">
               <Setter TargetName="TopPart" Property="Stroke" Value="#FFB5BECB"/>
               <Setter TargetName="TopPart" Property="Fill" Value="#FFEDF2F7"/>
               <Setter TargetName="BottomPart" Property="Stroke" Value="#FF6F9FFF"/>
               <Setter TargetName="BottomPart" Property="Fill" Value="#FF6F9FFF"/>
            </Trigger>
         </ControlTemplate.Triggers>
      </ControlTemplate>
   </ToggleButton.Template>
</ToggleButton>
 

Обновите свой комментарий. Шаблон элемента управления может состоять из нескольких именованных частей и визуальных состояний, которые определяют внешний вид и поведение элемента управления. Некоторые детали могут даже потребоваться для правильной работы элемента управления. Вы можете найти их в документации по стилям и шаблонам с примерами, но имейте в виду, что они могут быть неполными.

В случае ToggleButton , есть много визуальных состояний, например, наведение курсора мыши, Нажатие, Проверка и так далее. Вы можете просто определить раскадровки для каждого из них, чтобы определить внешний вид и переходы между состояниями. Этот подход использует VisualStateManager , который является альтернативой стилям и триггерам. Существует множество учебных пособий. Ваш шаблон может выглядеть следующим образом. При необходимости добавляйте раскадровки в состояния. Более простым способом определения визуальных состояний, чем редактирование кода XAML, является использование Blend, где вы можете удобно редактировать их с помощью графического редактора. Обзор см. в разделе Blend 2015: Создание визуальных состояний или аналогичных руководствах.

 <ToggleButton Content="Templated Toggle Button">
   <ToggleButton.Template>
      <ControlTemplate TargetType="{x:Type ToggleButton}">
         <!-- ...here might be a container that you did not provide in your question. -->
         <Canvas x:Name="MyCanvas"
                 Width="180"
                 Height="180"
                 Canvas.Left="0"
                 Canvas.Top="0"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Top">
            <VisualStateManager.VisualStateGroups>
               <VisualStateGroup x:Name="CommonStates">
                  <VisualState x:Name="Normal" />
                  <VisualState x:Name="MouseOver">
                     <Storyboard>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="TopPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="#FFB5BECB" />
                        </ColorAnimationUsingKeyFrames>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="TopPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="#FFEDF2F7" />
                        </ColorAnimationUsingKeyFrames>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="BottomPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="#FF6F9FFF" />
                        </ColorAnimationUsingKeyFrames>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="BottomPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="#FF6F9FFF" />
                        </ColorAnimationUsingKeyFrames>
                     </Storyboard>
                  </VisualState>
                  <VisualState x:Name="Pressed">
                     <Storyboard>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="TopPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="DarkRed" />
                        </ColorAnimationUsingKeyFrames>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="TopPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="Red" />
                        </ColorAnimationUsingKeyFrames>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="BottomPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="Blue" />
                        </ColorAnimationUsingKeyFrames>
                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)"
                                                      Storyboard.TargetName="BottomPart">
                           <EasingColorKeyFrame KeyTime="0"
                                                Value="Blue" />
                        </ColorAnimationUsingKeyFrames>
                     </Storyboard>
                  </VisualState>
                  <VisualState x:Name="Disabled" />
               </VisualStateGroup>
               <VisualStateGroup x:Name="CheckStates">
                  <VisualState x:Name="Checked" />
                  <VisualState x:Name="Unchecked" />
                  <VisualState x:Name="Indeterminate" />
               </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <Path x:Name="TopPart"
                  Stretch="Fill"
                  StrokeLineJoin="Miter"
                  Stroke="#FFB5BECB"
                  Fill="#FFCDD5DE"
                  Data="F1 M 90,18C 109.882,18 127.882,26.0589 140.912,39.0883L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 90,18 Z " />
            <Path x:Name="BottomPart"
                  Stretch="Fill"
                  StrokeThickness="1"
                  StrokeLineJoin="Miter"
                  Stroke="#FF13487E"
                  Fill="#FF13487E"
                  Data="F1 M 89.9999,5.00005C 113.472,5.00005 134.722,14.514 150.104,29.896L 152.225,27.7746C 136.301,11.8497 114.301,2.00002 90,2.00002L 89.9999,5.00005 Z" />
         </Canvas>
      </ControlTemplate>
   </ToggleButton.Template>
</ToggleButton>
 

Комментарии:

1. Большое спасибо, что нашли для меня решение. Я могу разобраться с этим прямо сейчас! @thatguy

2. На самом деле мне нужны дополнительные состояния для IsPressed и IsChecked (Свойства для a ToggleButton ). К сожалению, они не работают с наличием Canvas в качестве контейнера, потому Canvas что у них есть другие Template Properties . У вас есть какие-нибудь идеи, что еще я мог бы положить в качестве контейнера для моего paths ? Заранее благодарю вас!

3. Это здорово! Я займусь этим как можно скорее. Спасибо!