How to use VisualState AdaptiveTrigger to change ListView Item FontSize

瘦欲@ 提交于 2019-12-01 11:45:03

We can't use AdaptiveTrigger for an element inside the DataTemplate. You should use UserControl to do it. This answer may help you. If you want a video tutorial then this video may help you. But I have a little workaround for it.

Here is my method:

  1. Create a TextBlock outside the DataTemplateand set Visibility="Collapsed"

    <TextBlock Name="SetFontSize" Visibility="Collapsed"/>
    

    Note: You could also use BindableValueHolder instead of this and set the Value property of it using AdaptiveTrigger.

    <helpers:BindableValueHolder x:Name="SetFontSize"/>
    
  2. Use AdaptiveTrigger to change the FontSize of this TextBlock

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="NormalStateReadView">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="SetFontSize.FontSize" Value="20" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    
        <VisualStateGroup>
            <VisualState x:Name="WideStateReadView">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="720" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="SetFontSize.FontSize" Value="30" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    
  3. DataBind the FontSize of the TextBlock inside the DataTemplate to the outer TextBlock

    <TextBlock FontSize="{Binding Path=FontSize, ElementName=SetFontSize}"/>
    

Here is your code:

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState x:Name="NormalStateReadView">
            <!-- VisualState to be triggered when window width is <720 effective pixels -->
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="0" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="SetFontSize.FontSize" Value="20" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>

    <VisualStateGroup>
        <VisualState x:Name="WideStateReadView">
            <!-- VisualState to be triggered when window width is >=720 effective pixels -->
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="720" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="SetFontSize.FontSize" Value="30" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<TextBlock Name="SetFontSize" Visibility="Collapsed"/>
<ListView x:Name="listView">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextBlock FontSize="{Binding Path=FontSize, ElementName=SetFontSize}" Text="{Binding MyItem}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

You will need to wrap your your template inside a UserControl for adaptive triggers to work; also the visual states should go inside the template as well, and make sure it's under the first direct child (i.e. Grid) of the UserControl. I see you have defined two visual state groups but really you just need one.

<ListView.ItemTemplate>
    <DataTemplate>
        <UserControl>
            <Grid>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup>
                        <VisualState x:Name="NarrowState">
                            <VisualState.StateTriggers>
                                <AdaptiveTrigger MinWindowWidth="0" />
                            </VisualState.StateTriggers>

                            <VisualState.Setters>
                                <Setter Target="Title.(TextBlock.FontSize)" Value="24" />
                            </VisualState.Setters>
                        </VisualState>

                        <VisualState x:Name="WideState">
                            <VisualState.StateTriggers>
                                <AdaptiveTrigger MinWindowWidth="720" />
                            </VisualState.StateTriggers>

                            <VisualState.Setters>
                                <Setter Target="Title.(TextBlock.FontSize)" Value="36" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>

                <TextBlock x:Name="Title" Text="{Binding Property1}" />
            </Grid>
        </UserControl>
    </DataTemplate>
</ListView.ItemTemplate>

Update

Here is what I think a much more flexible solution. It needs some code to setup but the outcome is that you get clean, reusable and readable code.

The idea is to obtain a reference of the top level VisualStateGroup which is defined outside of the ListView, mostly at the Page level.

Then, create three VisualStates (i.e. Narrow, Normal & Wide) and attach them to a new VisualStateGroup which should belong to the first child of the UserControl.

Once we have referenced these two VisualStateGroups, we can monitor the top level one's CurrentStateChanged and update the state in the second one accordingly.

All the logic above can be wrapped by a Behavior from the UWP XAML Behavior nuget package.

Once the Behavior in place, you can define your inner states as easy as -

<DataTemplate>
    <UserControl>
        <Interactivity:Interaction.Behaviors>
            <local:VisualStateInTemplateBehavior ParentVisualStateGroup="{Binding ElementName=AdaptiveVisualStates}">
                <local:VisualStateInTemplateBehavior.NarrowState>
                    <VisualState x:Name="Narrow">
                        <VisualState.Setters>
                            <Setter Target="Title.(TextBlock.FontSize)" Value="24" />
                        </VisualState.Setters>
                    </VisualState>
                </local:VisualStateInTemplateBehavior.NarrowState>

                <local:VisualStateInTemplateBehavior.NormalState>
                    <VisualState x:Name="Normal">
                        <VisualState.Setters>
                            <Setter Target="Title.(TextBlock.FontSize)" Value="32" />
                        </VisualState.Setters>
                    </VisualState>
                </local:VisualStateInTemplateBehavior.NormalState>

                <local:VisualStateInTemplateBehavior.WideState>
                    <VisualState x:Name="Wide">
                        <VisualState.Setters>
                            <Setter Target="Title.(TextBlock.FontSize)" Value="40" />
                        </VisualState.Setters>
                    </VisualState>
                </local:VisualStateInTemplateBehavior.WideState>
            </local:VisualStateInTemplateBehavior>
        </Interactivity:Interaction.Behaviors>

Working Demo


Feel free to check out a working sample here.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!