Visual Basic, VB .NET, ASP, Active X, Access, SQL Server

WPF: alterando propriedades no container por triggers no content

Imagine, por exemplo, que você tenha um controle MsgBox e queira que o objeto Window que exibir este controle tenha a propriedade ResizeMode atribuída automaticamente. A forma de se fazer isto é criar um Trigger no template do controle MsgBox que converta o valor de uma propriedade no MsgBox para o valor desejado de se atribuir à propridade do objeto Window. Você pode conseguir isto de uma forma direta usando uma propriedade do controle que você converta (se necessário) para o valor desejado de se atribuir à propriedade do container. Veja abaixo como ficaria o trigger usando um "value converter": 

<Trigger Property="IsVisible" Value="True">

    <Setter Property="IsEnabled" Value="{Binding Mode=OneWayToSource, Path=ResizeMode, RelativeSource={RelativeSource AncestorType={x:Type Window}}, Converter={StaticResource BoolToResizeMode}}" />

</Trigger>

Acima, foi assumido que a propriedade IsEnabled do controle MsgBox terá o valor True constante. No caso disto não poder ser garantido, você pode criar uma propriedade para isto que já retorne um valor do tipo necessário, desta forma dispensando o value converter. O exemplo acima foi feito com value converter, porque, em alguns padrões de programação, o container exibe um tipo de classe que você não vai querer que contenha código comprometido com à tecnologia de exibição. Exemplo: o padrão Model-View-ViewModel.

Também foi assumido que você criou um value converter para transformar o valor True no valor desejado para a propriedade ResizeMode e definiu um recurso com x:Key igual a "BoolToResizeMode" para poder atribui-lo à propriedade Converter do binding. Exemplo:

 <local:BoolToResizeModeConverter x:Key="BoolToResizeMode" />

Você pode ter triggers para diferentes tipos de containeres e poderá usar seu controle sem preocupar-se com as configurações do container em que ele for adicionado.

Configurando muitas propriedades no container

Um inconveniente porém surge quando você tem de configurar muitas propriedades no container. Você não pode ter múltiplos setters para a mesma propriedade no trigger.  No exemplo acima, foi usada a propriedade IsEnabled no setter. Uma forma de fazer as coisas mais limpas e genéricas é criar "attached properties". Na própria classe do container ou numa classe que lhe seja conveniente, você pode criar "attached properties" para o tipo UIElement e usá-las nos seus triggers do mesmo modo que usou uma propriedade colhida por conveniência.

Veja abaixa uma propriedade do tipo attached criada numa classe Utilities para usar no trigger do exemplo acima.

Public NotInheritable Class Utilities

Private Sub New()

End Sub

Public Shared ReadOnly AuxResizeModeProperty As DependencyProperty = DependencyProperty.RegisterAttached("AuxResizeMode", GetType(ResizeMode), GetType(GenericDialog), New PropertyMetadata(ResizeMode.NoResize, Nothing))

Public Shared Function GetAuxResizeMode(element As UIElement) As ResizeMode

If element Is Nothing Then

Throw New ArgumentNullException("element")

End If

Return DirectCast(element.GetValue(AuxResizeModeProperty), ResizeMode)

End Function

Public Shared Sub SetAuxResizeMode(element As UIElement, value As ResizeMode)

If element Is Nothing Then

Throw New ArgumentNullException("element")

End If

element.SetValue(AuxResizeModeProperty, value)

End Sub

End Class

O trigger ficaria assim:

<Trigger Property="IsVisible" Value="True">

    <Setter Property="Utilities.AuxResizeMode" Value="{Binding Mode=OneWayToSource, Path=ResizeMode, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />

</Trigger>

Dentro do mesmo trigger acima, você poderia ter outros setters usando outras attachedproperties para atribuir valores a outras propriedades do objeto Window. Neste exemplo, nem foi preciso usar o converter, porque já criamos a propriedade com o valor padrão ResizeMode.NoResize.