Используйте триггер стиля для установки свойства вложенного объекта

#wpf #xaml

#wpf #xaml

Вопрос:

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

 <UserControl ...>
  <Canvas Name="canvas" Height="22" Width="22">
      <Canvas.Resources>
          <Style TargetType="Canvas">
              <Style.Triggers>
                  <Trigger Property="IsMouseOver" Value="false">
                      <Setter Property="polygon.Stroke" Value="#EEEEEE"/>
                  </Trigger>
                  <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="polygon.Stroke" Value="Aqua"/>
                </Trigger>
              </Style.Triggers>
          </Style>
      </Canvas.Resources>
      <Polygon Points="11,1 16,6 16,16 11,21" Name="polygon">
              <Polygon.Fill>
                  <SolidColorBrush Color="#EEEEEE"/>
              </Polygon.Fill>
      </Polygon>
  </Canvas>
</UserControl>
  

Однако установщик не видит «полигон».

Ответ №1:

Вы не можете использовать Setters это так, если вы используете такую нотацию, движок будет искать вложенное свойство, или если Style.TargetType для свойства типа перед точкой было установлено значение no.

Вероятно, проще всего применить стиль к самому полигону и использовать a DataTrigger , который привязывается к Canvas , чтобы вы могли запускать его свойства.

   <Polygon Points="11,1 16,6 16,16 11,21" Name="polygon">
       <Polygon.Fill>
           <SolidColorBrush Color="#EEEEEE"/>
       </Polygon.Fill>
       <Polygon.Style>
          <Style TargetType="{x:Type Polygon}">
             <Style.Triggers> 
                <DataTrigger
                   Binding="{Binding Path=IsMouseOver,
                                     RelativeSource={RelativeSource
                                     AncestorType={x:Type Canvas}}}"
                   Value="True">
                   <Setter Property="Stroke" Value="Red"/>
                </DataTrigger>
             </Style.Triggers>
          </Style>
       <Polygon.Style>
  </Polygon>
  

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

1. Это работает, но все равно только тогда, когда мышь находится над полигоном, а не над остальной частью холста. 🙁

2. @Badiboy: Ну, как указано в другом ответе, вам нужно установить фон на холсте, иначе проверка на попадание не выполняется.

3. @AngelWPF: Если я не добавляю код, который является преднамеренным большую часть времени, это может привести к тому, что люди будут копировать и вставлять, а не понимать концепцию. Например, ваш код используется RelativeSource в привязке, хотя могут быть и другие способы, поэтому, даже если код не копируется, определенный метод усиливается поверх общей концепции.

4. @H.B., я подумал, что, поскольку вы уже объяснили ответ, код поможет начинающему разработчику получить более четкое представление. Я, например, сам когда-то был одним из них и много боролся, когда это были только слова объяснения, поскольку это еще больше запутало бы меня. Еще раз извините, что отредактировал ваш ответ. Вы можете удалить его, если хотите.

5. @H.B. Я заменяю HitTestCore для этого пользовательского элемента управления, поэтому события обрабатываются, даже если в canvas нет фона. Однако я попытаюсь установить фон…

Ответ №2:

Попробуйте EventTrigger , потому что другие виды триггеров вы могли бы использовать только в шаблонах или стилях. И мы уже знаем этот стиль.Триггер не разрешает ваш сценарий. Итак, вот рабочий пример для вас:

 <Canvas Name="canvas" Height="22" Width="22">
    <Polygon Points="11,1 16,6 16,16 11,21" Name="polygon">
        <Polygon.Fill>
            <SolidColorBrush x:Name="brush" Color="#EEEEEE"/>
        </Polygon.Fill>
        <Polygon.Triggers>
            <EventTrigger RoutedEvent="UIElement.MouseEnter">
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetName="brush" Storyboard.TargetProperty="Color">
                        <ColorAnimation From="#EEEEEE" To="Aqua" Duration="00:00:00.01" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger RoutedEvent="UIElement.MouseLeave">
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetName="brush" Storyboard.TargetProperty="Color">
                        <ColorAnimation From="Aqua" To="#EEEEEE" Duration="00:00:00.01" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Polygon.Triggers>
    </Polygon>
</Canvas>
  

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

1. Вы могли бы сделать то же самое с обычным триггером ( Trigger.EnterActions amp; Trigger.ExitActions ), дело в том, что это анимация, которая работает по-другому. Кроме того, ваш пример больше не запускается на холсте, а на самом полигоне.

2. Для ввода / вывода вам нужно свойство IsMouseOver, которое является частью IInputInterface. Но ни Canvas, ни Polygon не имеют его реализации.

3. Canvas прозрачен, поэтому маршрутизируемые события MouseEnter / MouseLeave не будут запускаться. Вам нужно указать для него некоторый фон, по крайней мере, почти прозрачный.

4. Кажется, что «RoutedEvent» будет работать на полигоне только тогда, когда мышь будет находиться над полигоном, потому что он перенаправляется от родительского к дочернему, если оба они находятся под точкой события…

5. @invisible: то, что холст в примере прозрачен, не имеет значения, и как полигон, так и холст имеют IsMouseOver, так о чем вы говорите?

Ответ №3:

Он ищет свойство холста с именем ‘polygon’, которое, в свою очередь, имеет свойство с именем ‘Stroke’. Вам нужно использовать TargetName, если вы хотите, чтобы установщик был нацелен на другой объект.

 <Setter TargetName="polygon" Property="Stroke" Value="#EEEEEE" />
  

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

1. Я попробовал это. Но «свойство TargetName не может быть установлено в установщике стиля».

2. Яйцо на лице. Я всегда забываю об этом небольшом ограничении.