microsoft / xaml-standard

XAML Standard : a set of principles that drive XAML dialect alignment
Other
804 stars 50 forks source link

(Add Triggers, DataTrigger, EventTrigger,...) [and/or] VisualState #195

Open GeraudFabien opened 7 years ago

GeraudFabien commented 7 years ago

Hello, I have looking for triggers, VisualState, ... The only thinks i found was https://github.com/Microsoft/xaml-standard/issues/106. I hope it's not a duplicate since i'm talking about trigger (WPF and Xamarin.Form way) this thread is more about UWP Way. Personnaly I don't really have preference. To be true i have done more projet in WPF and didn't use enougth (Personnal project only with not "trigger") to have an idea on this subject.

Thanks

mfe- commented 7 years ago

I think Style Data/Triggers would be a great feature. Since UWP doesn't provide style triggers, we have to

I started with WPF and later UWP and XF. In UWP one of the first questions to myself was, where are those style triggers? So I created a question on SO. I think the upvotes speak for themselves regarding the feature request.

What is cool about the Microsoft.Xaml.Interactivity is that it provides comparison operators like equal, greater than, lesser than and so on. It would be awesome to have this feature in XAML standard too. But if not, we could achieve the comparison operators with Converters.

An advantage of the Core:DataTriggerBehavior is that I can add them to a specific control very fast. Consider the example:

    <TextBlock>
        <i:Interaction.Triggers>
            <ei:DataTrigger Binding="{Binding Path=IsCommandXYExecuted, UpdateSourceTrigger=PropertyChanged}" Comparison="Equal" Value="False">
                <inf:SetProperty TargetObject="{Binding Path=.,RelativeSource={RelativeSource AncestorType={x:Type TextBlock}}}" PropertyName="Foreground" Value="Red" />
                </ei:DataTrigger> 
        </i:Interaction.Triggers>
    </TextBlock>

7 lines vs. 11

 <TextBlock>
        <TextBlock.Style>
            <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=IsCommandXYExecuted, UpdateSourceTrigger=PropertyChanged,Converter=SomeBooleanConverter}" Value="True">
                        <Setter Property="Foreground" Value="Red" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>

So I use Style DataTrigger/Triggers if an event should be applied to a lot of Controls. If I need to use a DataTrigger only for one control I prefer the usage of Core:DataTriggerBehavior.

Regarding examples, I use Triggers and Datatriggers a lot. I'm using IsFocused, IsMouseOver (like the example in the first post), querying a property of the ViewModel (above example) to show/hide a Control and so on.

Some other examples:

    <Style TargetType="{x:Type ui:EdgeVisualization}">
        <Style.Triggers>
            <Trigger Property="IsFocused" Value="True">
                <Setter Property="StrokeThickness" Value="2" />
            </Trigger>
        </Style.Triggers>
    </Style>
    <EventTrigger RoutedEvent="GotFocus">
        <BeginStoryboard>
            <Storyboard>
                <ThicknessAnimation Storyboard.TargetProperty="BorderThickness"  From="1,1,1,1" To="2,2,2,2" FillBehavior="Stop" Duration="00:00:02.000" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=IsFocused,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:VertexVisualization}},UpdateSourceTrigger=PropertyChanged}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard Storyboard="{StaticResource BorderThicknessAnimationDown}"/>
            </DataTrigger.EnterActions>  
        </DataTrigger>
    </Style.Triggers>

    <Style.Triggers>
        <Trigger Property="IsKeyboardFocusWithin" Value="True">
            <Setter Property="Template" Value="{StaticResource VertexVisualizationTextBox}" ></Setter>
        </Trigger>
        <Trigger Property="IsKeyboardFocusWithin" Value="False">
            <Setter Property="Template" Value="{StaticResource VertexVisualizationTextBlock}" ></Setter>
        </Trigger>
    </Style.Triggers>

    <Style TargetType="{ x:Type Button }">
        <Style.Triggers>
            <DataTrigger Binding="{ Binding ShowRandomReceipe,RelativeSource={ RelativeSource Mode=FindAncestor,AncestorType={ x:Type local:RecipeListControl } } }" Value="False">
                <Setter Property="Visibility" Value="Collapsed" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

    <Style TargetType="{ x:Type Expander }" >
        [...]
        <DataTemplate.Triggers>
            <DataTrigger Binding="{ Binding RelativeSource={ RelativeSource Mode=FindAncestor,AncestorType={ x:Type Expander } }, Path=IsExpanded }" Value="True">
                <DataTrigger.EnterActions>
                    <BeginStoryboard Storyboard="{ StaticResource OpenExpanderAnimation }" />
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <BeginStoryboard Storyboard="{ StaticResource CollapseExpanderAnimation }" />
                </DataTrigger.ExitActions>
            </DataTrigger>
        </DataTemplate.Triggers>
        [...]
    </Style>
GeraudFabien commented 7 years ago

VisualState can be used as triggers replacement in UWP & Silverlight.(http://putridparrot.com/blog/visualstatemanager-and-alternative-to-triggers/). It exist in WPF, UWP, Silverlight and seem pretty easy to add in Xamarin.Form. It exist for many years. And you can easly add your own trigger to do exactly what you want (ex: https://github.com/dotMorten/WindowsStateTriggers). I see your StackOverflow Question. Why do you say:

Use Animations or VisualStateTriggers. Both seem to be wrong if I use them not to adjust the controls to the screen.

mfe- commented 7 years ago

VisualState can be used as triggers replacement in UWP & Silverlight.(http://putridparrot.com/blog/visualstatemanager-and-alternative-to-triggers/). It exist in WPF, UWP, Silverlight and seem pretty easy to add in Xamarin.Form. It exist for many years. And you can easly add your own trigger to do exactly what you want (ex: https://github.com/dotMorten/WindowsStateTriggers). I see your StackOverflow Question. Why do you say Use Animations or VisualStateTriggers. Both seem to be wrong if I use them not to adjust the controls to the screen.

Imho Style Trigger and VSM are two different things. With Style.Triggers you can say "Apply this Style to all controls in my app which further applies your defined Triggers/DataTriggers. A Visual State Manager can't be applied (in UWP, SL, WPF?) directly to a Style and therefore you can't achieve the same thing with a VSM. Maybe this was intended by design when releasing the VSM?

The posted link describes a workaround or hack, how to fill the missing gap of style triggers in SL with VSM and a control template. Sry, I didn't read the link carefully enough. The usage of a VSM in ControlTemplates for defining and controlling Visual States like IsPressed, IsMouseHover ... are absolutely legit. Anyway using VSM because Data-/Triggers are missing, feels wrong.

Some disadvantages of a VSM workaround:

I would use the visual state manager only to adjust my control/page/window to specific visual states. E.g. the available screen size is only 400 px or my control is used on a specific platform. Style.Triggers Style.DataTriggers can then be used for stuff which is not Visual State related.

Both, Style.Triggers and VSM are legitimate for the XAML Standard.

GeraudFabien commented 7 years ago

I have added Visual state to the discution (In the title). I will write the definition later.