2015-05-21 2 views
2

Как стилизовать элемент, основанный на изменениях дочерних свойств? Я бы принял другой подход, но желаемый результат состоит в том, что родительское свойство задано определенным образом, если дочернее свойство (IsPressed) истинно.Как бы связать DataTrigger с дочерним свойством из определенного ресурсом стиля?

Если мы стилизация один именованный элемент с стилем в онлайн мы можем просто идентифицировать наш ребенок с помощью ELEMENTNAME, но может быть даже менее специфичны и использовать Child.IsPressed:

<Border Name="parentBorder" Padding="20"> 
    <Button Name="childButton" Content="Don't Push Me Bro"/> 
    <Border.Style> 
     <!--Now how can I do this from a static resource where I don't know the elementname?--> 
     <Style TargetType="Border"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Child.IsPressed}" Value="True"> 
        <Setter Property="Background" Value="Blue"/> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Border.Style> 
</Border> 

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

<Style x:Key="ButtonBorder" TargetType="{x:Type Border}"> 
    <Style.Triggers>     
     <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Child.IsPressed}" Value="True"> 
      <Setter Property="Background" Value="Blue"/> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 

Каков наилучший подход , или что мне не хватает? Я вижу, что когда «Ребенок» используется как встроенный стиль, intellisense окрашивает Child по-другому, и я уверен, что это что-то значит. Предполагается ли что-то о типе Ребенка из определяемых ресурсами стилей, просто ничего хорошего?

ответ

2

Вы можете использовать прикрепленные свойства для этого. Например:

public static class Attached 
{ 
    public static readonly DependencyProperty RelatedControlProperty = DependencyProperty.RegisterAttached(
     "RelatedControl", typeof(UIElement), typeof(Attached)); 

    public static void SetRelatedControl (DependencyObject element, UIElement value) 
    { 
     element.SetValue(RelatedControlProperty, value); 
    } 

    public static UIElement GetRelatedControl (DependencyObject element) 
    { 
     return (UIElement)element.GetValue(RelatedControlProperty); 
    } 
} 

Это свойство не имеет логики, оно просто используется для «подключения» элементов управления любым способом.

В стиле, вы читаете вложенное свойство вашего контроля:

<Style x:Key="ButtonBorder" TargetType="{x:Type Border}"> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding 
       RelativeSource={RelativeSource Self}, 
       Path=(local:Attached.RelatedControl).IsPressed}" Value="True"> 
      <Setter Property="Background" Value="Blue"/> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 

И когда вы создаете свой контроль, установить вложенное свойство для дочернего элемента управления:

<Border Name="parentBorder" Padding="20" Style="{StaticResource ButtonBorder}" 
     local:Attached.RelatedControl="{x:Reference childButton}"> 
    <Button Name="childButton" Content="Don't Push Me Bro"/> 
</Border> 

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

Если вы действительно хотите использовать стиль границы только для границ, содержащих только кнопки, возможно, вам стоит просто переопределить шаблон кнопки.

+0

Ага - так я был на правильном пути, думая, что он просто не знает достаточно о Ребенке, и это способ сказать ему, какого типа ожидать? С прикрепленным свойством он все еще не указан в стиле, но я предположил, что это было частью проблемы. Я также предполагал, что он попытается просто потерпеть неудачу, если я применил стиль, когда ребенок не был кнопкой (или не имел IsPressed). –

+0

@JoshSutterfield Связывание будет бесшумно, если оно не сможет найти свойство, и триггер никогда не будет срабатывать. Если вы хотите быть абсолютно уверены, что для связывания используется только '' IsPressed', и вы ничего не можете использовать, вы можете использовать это выражение: '(local: Attached.RelatedControl). (ButtonBase.IsPressed)'. Если вы хотите поддерживать элементы управления несколькими типами, вы можете использовать «PriorityBinding» и перечислить несколько привязок для каждого свойства. – Athari

+0

Удивительно, что он * не может * найти свойство в тех случаях, когда он есть. Случается столь же хрупкий подход использования {Binding ElementName = childButton, Path = IsPressed} из статического ресурса. Хорошо, да, это было бы компромиссом хрупкости для удобочитаемости и наличия всего в XAML, но я рад, что знаю более надежный способ. –

Смежные вопросы