AdaptiveTrigger and DataTemplate
Asked Answered
E

2

26

Will AdaptiveTrigger work in a DataTemplate?

That's my code i'm using to customize my ShellNavigation, it is working fine except the visual states. They will not trigger anything.

<shell:ShellHeadView x:Key="ShellHeadView_01">
    <shell:ShellHeadView.ContentTemplate>
        <DataTemplate>
            <Grid Margin="20,0">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup>
                        <VisualState x:Name="GreenBackgroundVisualState">
                            <VisualState.Setters>
                                <Setter Target="headViewLeft.Background" Value="Green" />
                            </VisualState.Setters>
                            <VisualState.StateTriggers>
                                <AdaptiveTrigger MinWindowWidth="1000"/>
                            </VisualState.StateTriggers>
                        </VisualState>
                        <VisualState x:Name="OrangeBackgroundVisualState">
                            <VisualState.Setters>
                                <Setter Target="headViewLeft.Background" Value="Orange" />
                            </VisualState.Setters>
                            <VisualState.StateTriggers>
                                <AdaptiveTrigger MinWindowWidth="2000"/>
                            </VisualState.StateTriggers>
                        </VisualState>
                        <VisualState x:Name="RedBackgroundVisualState">
                            <VisualState.Setters>
                                <Setter Target="headViewLeft.Background" Value="Red" />
                            </VisualState.Setters>
                            <VisualState.StateTriggers>
                                <AdaptiveTrigger MinWindowWidth="3000"/>
                            </VisualState.StateTriggers>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid Grid.Column="0" x:Name="headViewLeft" Width="100" Height="90">

                </Grid>
Ebenezer answered 19/8, 2015 at 6:58 Comment(0)
G
62

Try wrapping your DataTemplate inside a UserControl like this -

<DataTemplate>
    <UserControl>
        <Grid>
            <VisualStateManager.VisualStateGroups>
            ...
        </Grid>
    </UserControl>
</DataTemplate>

Looks like any Control that has got a Content property will work. That's why UserControl works, so does a ContentControl.

So if you replace the UserControl with a ContentControl and give it an empty Style. It should work too.

<Style x:Key="EmptyContentControlStyle" TargetType="ContentControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ContentControl" />
        </Setter.Value>
    </Setter>
</Style>

<DataTemplate>
    <ContentControl Style="{StaticResource EmptyContentControlStyle}">
        <Grid>
            <VisualStateManager.VisualStateGroups>
            ...
        </Grid>
    </ContentControl>
</DataTemplate>
Gunther answered 19/8, 2015 at 10:10 Comment(9)
How can I use this to make dynamically created list items working?ListView listView = new ListView(); listView.ItemsSource = source.Articles; listView.Template = ???; listView.IsItemClickEnabled = true; listView.ItemClick += OpenArticle_ItemClick; listView.SelectionMode = ListViewSelectionMode.None;Roband
FWIW, UserControl works great, but ContentControl does not. Still a great answer!Conflux
@EricLiprandi hmm did you give your ContentControl an empty style?Gunther
I missed that part :) - I guess the UserControl is cleaner for me then... I can't think of a functional difference in this case between UserControl and ContentControl.Conflux
@EricLiprandi yeah UserControl is definitely more convenient. :)Gunther
Also, make sure that the VisualStateManager is not a direct child of UserControl or ContentControlAlum
this approach works, but the StateTrigger gets eventually garbage collected, which leads to an error later on.Vibratory
Here is another answer that addresses states in ListView's DataTemplate.Gunther
In general I would heavily recommend against putting user controls inside datatemplates. User controls are SLOW, so having them in templates that are used over and over again can be bad for performance (custom controls with control templates are a better alternative for that).Newlin
N
0

Create two data templates. Use the adaptive trigger to change the ItemTemplate on your ItemsControl

TBH it feels a bit weird to me to put adaptive triggers inside a generic template, rather than in the page view.

In general I would heavily recommend against putting user controls inside datatemplates as is suggested in another answer. User controls are SLOW, so having them in templates that are used over and over again can be bad for performance (custom controls with control templates are a better alternative for that).

You could also create a custom control that switches between templates. Example:

public class AdaptiveControl : ContentControl
{
    public AdaptiveControl()
    {
        SizeChanged += AdaptiveControl_SizeChanged;
    }

    private void AdaptiveControl_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        Update();
    }
    private void Update() 
    {
        if (ActualWidth < Size)
            ContentTemplate = SmallTemplate;
        else
            ContentTemplate = LargeTemplate;
    }

    public double Size
    {
        get { return (double)GetValue(SizeProperty); }
        set { SetValue(SizeProperty, value); }
    }

    public static readonly DependencyProperty SizeProperty =
        DependencyProperty.Register(nameof(Size), typeof(double), typeof(AdaptiveControl), new PropertyMetadata(200d, (s, e) => ((AdaptiveControl)s).Update()));

    public DataTemplate SmallTemplate
    {
        get { return (DataTemplate)GetValue(SmallTemplateProperty); }
        set { SetValue(SmallTemplateProperty, value); }
    }

    public static readonly DependencyProperty SmallTemplateProperty =
        DependencyProperty.Register(nameof(SmallTemplate), typeof(DataTemplate), typeof(AdaptiveControl), new PropertyMetadata(null, (s, e) => ((AdaptiveControl)s).Update()));


    public DataTemplate LargeTemplate
    {
        get { return (DataTemplate)GetValue(LargeTemplateProperty); }
        set { SetValue(LargeTemplateProperty, value); }
    }

    public static readonly DependencyProperty LargeTemplateProperty =
        DependencyProperty.Register(nameof(LargeTemplate), typeof(DataTemplate), typeof(AdaptiveControl), new PropertyMetadata(null, (s, e) => ((AdaptiveControl)s).Update()));

}
Newlin answered 19/11, 2021 at 16:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.