Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

时间:2021-12-11 15:51:13

最近好久没有写博客了,今天分享一下关于工作中遇到的关于Visibility变化而引起的布局变化的问题。 

先以一个小例子开场,需求: 新浪微博 添加账号界面中需要有“登陆”按钮,当用户点击此按钮后,需要把按钮换成ProgressRing。如果登陆不成功,弹出错误信息并把ProgressRing替换成“登陆”按钮。

如下图:

Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

在按钮与ProgressRing切换的时候我们的一般做法是两种:

1. 用两个Visibility属性隐藏其中按钮,然后再显示;

2. 删除按钮、添加ProgressRing;删除ProgressRing,添加按钮;

第二种比较浪费资源,所以大家都把第一种作为较为常用的方法,即: 用Visibility属性来控制某些UI元素的隐藏与否,特别是需要重复切换的。

 

现在切入正题,先上图:

Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

想必玩过Win8开发的童鞋们一定不陌生,这是在VS中创建GridView模版的应用,启动后的首页面。

需求是:点击某一项,使其从界面中消失,但是布局不变,即:如果我任意删除一个单元,后面的单元会补充到前面去,中间不会有空白空间。

乍一看跟上面例子的需求类似,可以在数据集的单元数据中添加个Visibility类型的属性,通过绑定到ItemTemplate中的最外层布局控件上来实现隐藏。但是你真的这么做了,却发现结果是这样的:

Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

 

Wow! 为什么? 如果你看看GridView的代码,并试图修改点内容,或许会有所发现:

<GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Grouped Items"
            Grid.RowSpan="2"
            Padding="116,137,40,46"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
            SelectionMode="None"
            IsSwipeEnabled="false"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick">

            <GridView.ItemsPanel>
                <ItemsPanelTemplate>                        
                    <VirtualizingStackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            <GridView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Margin="1,0,0,6">
                                <Button
                                    AutomationProperties.Name="Group Title"
                                    Click="Header_Click"
                                    Style="{StaticResource TextPrimaryButtonStyle}" >
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
                                        <TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>
                                    </StackPanel>
                                </Button>
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            <VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </GridView.GroupStyle>
        </GridView>

关键因素1:<GroupStyle.Panel>中的 VariableSizedWrapGrid

 如果把<GroupStyle.Panel>中的 VariableSizedWrapGrid替换成<StackPanel Orientation="Horizontal" Margin="0,0,80,0"/>,你会发现效果变成了这样:

Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

Group Title 1 中的 Item Titile 2的项被删除掉了以后,后面的元素都向前移动了,证明VariableSizedWrapGrid控件内部对Visibility变化导致的布局变化的支持度不是很好。(你注意到在ItemTitile2项被隐藏后,为什么中间的空间会比较大,不像其他元素一样?  这个留给大家去研究吧,卖个关子。。。)

 

关键因素2:WrapGrid

或许你的应用中不需要分组,也会出现类似的情况,那可能是这样的:

<GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Grouped Items"
            Grid.RowSpan="2"
            Padding="116,137,40,46"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
            SelectionMode="None"
            IsSwipeEnabled="false"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick">

            <GridView.ItemsPanel>
                <ItemsPanelTemplate>                        
                    <WrapGrid Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
        </GridView>

 

Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

同样的,隐藏某一项后,后面的元素并不会填充被隐藏元素的空间,而只是隐藏了那一项,剩下的位置不动。。。

Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

那你试试把WrapGrid换成 VirtualizingStackPanel,问题解决了。

Windows 8 系列(九):关于VariableSizedWrapGrid与WrapGrid 对Visibility变化而引起的布局变化的支持

你或许在问,如果这样改,空白的空间是解决了,但是我们的整体布局也被打乱了。。。

 

没错,其实这些都只是下下策,更多的是为了告诉大家,这几个控件对Visibility属性变化而引起的布局变化的支持程度,而相比较之下,或许从数据源中删除数据才是更好的解决方案,即解决了空白空间的问题,也解决了布局被打乱的问题。