必威体育Betway必威体育官网
当前位置:首页 > IT技术

SharedSizeGroup及Collapsed属性分析及窗口隐藏

时间:2019-06-16 10:43:10来源:IT技术作者:seo实验室小编阅读:59次「手机版」
 

collapsed

SharedSizeGroup及collapsed属性分析及窗口隐藏

tags: wpf C# XAML


由于设计需要,要实现一个类似《WPF揭秘》里的一个布局实例,先把最终需要实现的效果图贴上

281458002154674.gif-685kB

图片来源:WPF布局 - ShengM - 博客

这里面贴出了所有实例代码,但是没有具体分析,由于是新手,折腾了一上午才搞清楚里面的来龙去脉,这里记录一下。

起初需要实现的功能如图中紫色部分一样,当toolbox窗口关闭后可以自动占据其布局位置,同时当Toolbox窗口出现后,其可以自动让出其布局位置。在网上搜了很多,大家都说把需要隐藏对的窗口的Visibility设置为Collapsed就可以实现窗口隐藏,其余窗口自动占位的效果。于是试了一下,发现不行……然后在网上找到了这个布局实例以及其源码,对其进行了分析,找到之前失败的原因。

首先,把之前失败的布局代码贴出来:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Button Grid.RowSpan="1" content="Button" Margin="0,0,0,0" />
    <TabControl Grid.Row="1" Margin="0,0,0,0" TabstripPlacement="Right" Style="{DynamicResource TabControlStyleRotate}">
        <TabItem Content="111111" Style="{DynamicResource TabItemStyleRotate}" Header="About"/>
        <TabItem Header="About" Content="222222" Style="{DynamicResource TabItemStyleRotate2}"/>
    </TabControl>
    <Border Grid.Row="2" Background="AliceBlue">
        <TextBlock Text="bbbbb&#13;bbb&#13;bbb&#13;bbb&#13;bbb&#13;bbbba&#13;bbbb"/>
    </Border>
    <Border Grid.Row="3" Visibility="Collapsed">
        <TextBlock Text="aaaaa&#13;aaaaaa&#13;aaaaaaaaa&#13;aaaaaaa"/>
    </Border>
</Grid>

本来期望第三行能自动填补第四行的空缺的,结果却是这样……

1506059368.png-26.6kB

如果是有经验的开发人员……应该一眼就能看出问题,这里主要是给像我一样的新手来说明一下。

首先看一下MSDN对Collapsed的解释:

成员名称 说明
Collapsed 不显示元素,并且不在布局中为它保留空间
hidden 不显示元素,但是在布局中为元素保留空间
Visible 显示元素

所谓不在不居中为它保留空间,是指将该元素的尺寸当成了0,仅此而已。这里我之前就有一点误区,认为该元素的尺寸若为零,则其他元素会自动来对其进行补位,这显然是不成立的,因为在Grid布局中划分了网格区域后,所有空间将只会出现在对应的网格中,除非使用RowSpan这类属性来跨越多个网格部署。(若不指定网格,默认都出现在第一格中)

在布局中什么情况下才会补位?就目前我所知道的是只有在布局中,某个元素拥有“填充满剩余空间”这样的属性时才会自动补位,其实也就是执行其自身的“填充满剩余空间”这个属性。当然这个属性只是我这么称呼他。

目前来说,我常用到的元素中拥有“填充满剩余空间”这个属性的元素是“DockPanel”,还有没有其他的暂时不清楚。对于“StackPanel”这种布局,当把其中的某一个元素进行Collapsed后,其后面的元素会进行补位,但是不会进行伸缩填充,Collapsed前后效果如下图:

1506064053(1).png-8.2kB

20170922150824.png-7.8kB

这里将bbb进行Collapsed,这时ccc顶替了bbb的区域。但在“DockPanel”布局中,对于最后的那个元素的行为将是填充满剩余空间,所以想要实现本文第一个图中的效果必须使用“DockPanel”布局。下面将第一个图的XAML及C#源码贴出来,然后再对其实现进行分析。

首先是XAML代码:

<Window x:Class="VSUIDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        title="MainWindow">

    <DockPanel>

        <Menu DockPanel.Dock="Top">
            <MenuItem Header="File" />
            <MenuItem Header="Edit" />
            <MenuItem Header="View" />
            <MenuItem Header="Project" />
            <MenuItem Header="build" />
            <MenuItem Header="Debug" />
            <MenuItem Header="Team" />
            <MenuItem Header="Tool" />
            <MenuItem Header="Test" />
            <MenuItem Header="structure" />
            <MenuItem Header="Analysis" />
            <MenuItem Header="Window" />
            <MenuItem Header="Help" />
        </Menu>

        <StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
            <StackPanel.layoutTransform>
                <RotateTransform Angle="90" />
            </StackPanel.LayoutTransform>
            <Button x:Name="toolboxButton"
                    Content="Toolbox"
                    MouseEnter="toolboxButton_MouseEnter" />
            <Button x:Name="solutionButton"
                    Margin="2,0"
                    Content="Solution Explorer"
                    MouseEnter="solutionButton_MouseEnter" />
        </StackPanel>

        <Grid Grid.IsSharedSizeScope="True">

            <Grid x:Name="layer0Grid"
                  Panel.ZIndex="0"
                  MouseEnter="layer0Grid_MouseEnter">
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <Border Grid.ColumnSpan="2" Background="BlueViolet">
                    <TextBlock HorizontalAlignment="Center"
                               VerticalAlignment="Center"
                               FontSize="36"
                               Text="Start Page" />
                </Border>

                <GroupBox Grid.Row="1"
                          Margin="2"
                          BorderThickness="2"
                          Header="recent Projects">
                    ...
                </GroupBox>
                <GroupBox Grid.Row="1"
                          Grid.RowSpan="3"
                          Grid.Column="1"
                          Margin="2"
                          BorderThickness="2"
                          Header="Online Articles">
                    <listbox>
                        <ListBoxItem Content="Article #1" />
                        <ListBoxItem Content="Article #2" />
                        <ListBoxItem Content="Article #3" />
                        <ListBoxItem Content="Article #4" />
                    </ListBox>
                </GroupBox>

                <GroupBox Grid.Row="2"
                          Margin="2"
                          BorderThickness="2"
                          Header="Getting Started">
                    ...
                </GroupBox>
                <GroupBox Grid.Row="3"
                          Margin="2"
                          BorderThickness="2"
                          Header="Headlines">
                    ...
                </GroupBox>

            </Grid>

            <Grid x:Name="toolboxLayerGrid" Visibility="Collapsed">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ToolboxGroup" />
                </Grid.ColumnDefinitions>

                <GridSplitter Grid.Column="1"
                              Width="3"
                              HorizontalAlignment="Left" />

                <Grid x:Name="toolboxGrid"
                      Grid.Column="1"
                      Margin="3,0,0,0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Grid Background="LightBlue">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition Width="35" />
                        </Grid.ColumnDefinitions>
                        <TextBlock VerticalAlignment="Center"
                                   FontSize="18"
                                   Text="Toolbox"
                                   TextTrimming="CharacterEllipsis" />
                        <Button x:Name="toolboxLayerPinButton"
                                Grid.Column="1"
                                Click="toolboxLayerPinButton_Click">
                            <Image x:Name="toolboxImage"
                                   Width="24"
                                   Height="24"
                                   Source="Resource/Image/pin_float.png" />
                        </Button>
                    </Grid>
                    <ListBox Grid.Row="1" FontSize="16">
                        <ListBoxItem Content="Button" />
                        <ListBoxItem Content="CheckBox" />
                        <ListBoxItem Content="Label" />
                        <ListBoxItem Content="ComboBox" />
                        <ListBoxItem Content="ListBox" />
                    </ListBox>
                </Grid>

            </Grid>

            <Grid x:Name="solutionLayerGrid" Visibility="Collapsed">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition Width="Auto" SharedSizeGroup="SolutionGroup" />
                </Grid.ColumnDefinitions>

                <GridSplitter Grid.Column="1"
                              Width="3"
                              HorizontalAlignment="Left" />

                <Grid x:Name="solutionGrid"
                      Grid.Column="1"
                      Margin="3,0,0,0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition />
                    </Grid.RowDefinitions>

                    <Grid Background="LightBlue">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition Width="35" />
                        </Grid.ColumnDefinitions>
                        <TextBlock VerticalAlignment="Center"
                                   FontSize="18"
                                   Text="Solution Explorer"
                                   TextTrimming="CharacterEllipsis" />
                        <Button x:Name="solutionLayerPinButton"
                                Grid.Column="1"
                                Click="solutionLayerPinButton_Click">
                            <Image x:Name="solutionImage"
                                   Width="24"
                                   Height="24"
                                   Source="Resource/Image/pin_float.png" />
                        </Button>
                    </Grid>

                    <Border Grid.Row="1" Background="White">
                        <toolbar>
                            <Image Source="Resource/Image/copy.png" />
                            <Image Margin="2,0" Source="Resource/Image/paste.png" />
                            <Image Margin="2,0" Source="Resource/Image/refresh.png" />
                        </ToolBar>
                    </Border>


                    <TreeView Grid.Row="2">
                        <TreeViewItem Header="My Solution">
                            <TreeViewItem Header="Project #1" />
                            <TreeViewItem Header="Project #2" />
                            <TreeViewItem Header="Project #3" />
                        </TreeViewItem>
                    </TreeView>

                </Grid>

            </Grid>

        </Grid>

    </DockPanel>

</Window>

一段段来分析吧……

首先<Window></Window>这个就不说了……

然后是

<DockPanel>
    <Menu></Menu>
    <StackPanel></StackPanel>
    <Grid></Grid>
</DockPanel>

这个里面就是一个基本布局了,布局完了之后大致形状应该是酱紫:

微信截图_20170922152501.png-36.4kB

其中1是目录菜单,2是侧边按钮,3是中间的内容,这样,整个内容部分将是一个具有“填充满剩余空间”属性的区域。

其中1和2区域比较简单,就不分析了。

主要来看看3号区域,3号区域代码展开:

<Grid Grid.IsSharedSizeScope="True">

    <Grid x:Name="layer0Grid" Panel.ZIndex="0" MouseEnter="layer0Grid_MouseEnter"></Grid>

    <Grid x:Name="toolboxLayerGrid" Visibility="Collapsed"></Grid>

    <Grid x:Name="solutionLayerGrid" Visibility="Collapsed"></Grid>

<Grid/>

OK,玄机来了……起初一看,这不是操蛋的写法么?!!就我目前的认知水平,如果有一段这样的代码:

    <Grid>
        <Grid>
            <TextBlock Text="1111111111"/>
        </Grid>
        <Grid>
            <TextBlock Text="222222222"/>
        </Grid>
        <Grid>
            <TextBlock Text="33333333"/>
        </Grid>
    </Grid>

这是什么鬼……显示出来如下:

微信截图_20170922153810.png-10.7kB

可是上面的代码明明就是这样写的,为什么那几个框没有这样重叠?这里就是这个布局的一个技巧了,也是这个技巧造就了隐藏Toolbox窗口后,紫色界面立马填充满的“假象”。之所以说是“假象”,下面就来分析。

先来看layer0Grid这个布局:

<Grid x:Name="layer0Grid">
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <!--元素1-->
    <Border Grid.ColumnSpan="2" Background="BlueViolet"></Border>
    <!--元素2-->
    <GroupBox Grid.Row="1"></GroupBox>
    <!--元素3-->
    <GroupBox Grid.Row="1" Grid.RowSpan="3" Grid.Column="1"></GroupBox>
    <!--元素4-->
    <GroupBox Grid.Row="2"></GroupBox>
    <!--元素5-->
    <GroupBox Grid.Row="3"></GroupBox>

</Grid>

这里只分析主要代码,具体内容比较简单就直接忽略了。这里把3号区域分成4行2列的布局,其中最上面的紫色区域占用2列,布局完后,3号区域应该如图所示:

微信截图_20170922155135.png-53.3kB

其中1,2,3,4,5对应的是代码中注释的“元素x”。这个时候原来的3号区域已经被占满了,如果再在3号区域增加toolboxLayerGrid和solutionLayerGrid两个布局,则都将与layer0Grid布局发生重叠,但这里所利用的恰好是布局重叠。再来分析toolboxLayerGrid和solutionLayerGrid,这里只分析toolboxLayerGrid,solutionLayerGrid与toolboxLayerGrid是一个道理。

<Grid x:Name="toolboxLayerGrid" Visibility="Collapsed">
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="Auto" SharedSizeGroup="ToolboxGroup" />
    </Grid.ColumnDefinitions>

    <GridSplitter Grid.Column="1" Width="3" HorizontalAlignment="Left" />

    <Grid x:Name="toolboxGrid" Grid.Column="1" Margin="3,0,0,0"></Grid>

</Grid>

在这里,可以看到toolboxLayerGrid里面其实将3号区域分成了1行2列的形状,在第二列中有两个东西,一个是GridSplitter,一个是toolboxGrid,toolboxGrid中的Margin左边留3,是为了绘制GridSplitter留的空间,GridSplitter是手动调整窗口大小用的,具体用法这里不单独说。从这里可以看出,toolboxLayerGrid这个布局分成两列的良苦用心,它让真正的toolboxGrid暂用最右边的位置,toolboxGrid的宽度根据toolboxGrid中实际内容的宽度而定,但是3号区域在“DockPanel”中必须填充满所有剩余区域,所以这里把本来1列就可以表述完的toolboxGrid封装成了一个两列的toolboxLayerGrid,toolboxLayerGrid中的第一列的作用就是占位。toolboxLayerGrid与layer0Grid叠加后应为如下视图:

微信截图_20170922160748.png-93.4kB

其中蓝色部分为toolboxLayerGrid。一开始,toolboxLayerGrid的属性被设备为了Collapsed,所以,整个蓝色区域没有显示。但一旦将toolbox固定在屏幕上时,蓝色区域将被显示出来,这时,问题来了,layer0Grid将有一部分被toolboxGrid挡住,而不是我们看在第一个图中看到额当toolbox显示后,紫色区域缩回去一截那个效果。如果要实现缩回去的效果就要对layer0Grid做些手脚,这也是前面所说的“假象”的原因。

考虑这样一个问题,若layer0Grid变成这样:

微信截图_20170922161355.png-75kB

将原来本是两列的layer0Grid,增加一列,变成3列,也就是增加了一个6号区域,这个时候原来的元素1、元素3都会都会自动变小。前提是增加的一列是有固定宽度值的,否则一个没有内容又没有宽度值得列将直接被不显示了。

增加了6号区域后,若6号区域的大小正好等于toolboxGrid,这样就可以让toolboxLayerGrid和layer0Grid叠加后互不干扰了!

微信截图_20170922161804.png-99.1kB

再考虑一个更有趣的情况,若6号区域是一个能动态存在的区域,即:当toolboxGrid存在时,layer0Grid才有6号区域,否则layer0Grid没有6号区域,这样不就同时解决了两个问题么?

  • 两个Grid叠加遮挡问题
  • 紫色区域自动伸缩问题(当有6号区域时,1号区域变小,没有6号区域时1号区域自动占用6号区域的位置)

那么现在唯一的问题就是,如何动态创建和删除6号区域了,这部分代码在C#代码里:

public partial class MainWindow : Window
{
    private ColumnDefinition _cloneToolboxGrid;
    private ColumnDefinition _cloneSolutionGrid;
    private ColumnDefinition _cloneToToolboxLayerGrid;

    public MainWindow()
    {
        Initializecomponent();

        _cloneToolboxGrid = new ColumnDefinition { SharedSizeGroup = "ToolboxGroup" };
        _cloneSolutionGrid = new ColumnDefinition { SharedSizeGroup = "SolutionGroup" };
        _cloneToToolboxLayerGrid = new ColumnDefinition { SharedSizeGroup = "SolutionGroup" };
    }

    private void toolboxButton_MouseEnter(object sender, MouseEventArgs e)
    {
        toolboxLayerGrid.Visibility = System.windows.Visibility.Visible;
        toolboxLayerGrid.SetValue(Grid.ZIndexProperty, 2);

        if (solutionButton.Visibility == System.Windows.Visibility.Visible)
            solutionLayerGrid.Visibility = System.Windows.Visibility.Collapsed;
        else
            solutionLayerGrid.SetValue(Grid.ZIndexProperty, 1);
    }

    private void solutionButton_MouseEnter(object sender, MouseEventArgs e)
    {
        solutionLayerGrid.Visibility = System.Windows.Visibility.Visible;
        solutionLayerGrid.SetValue(Grid.ZIndexProperty, 2);

        if (toolboxButton.Visibility == System.Windows.Visibility.Visible)
            toolboxLayerGrid.Visibility = System.Windows.Visibility.Collapsed;
        else
            toolboxLayerGrid.SetValue(Grid.ZIndexProperty, 1);
    }

    private void layer0Grid_MouseEnter(object sender, MouseEventArgs e)
    {
        if (toolboxButton.Visibility == System.Windows.Visibility.Visible)
            toolboxLayerGrid.Visibility = System.Windows.Visibility.Collapsed;

        if (solutionButton.Visibility == System.Windows.Visibility.Visible)
            solutionLayerGrid.Visibility = System.Windows.Visibility.Collapsed;
    }

    private void toolboxLayerPinButton_Click(object sender, RoutedEventArgs e)
    {
        if (toolboxButton.Visibility == System.Windows.Visibility.Visible)
        {
            toolboxImage.Source = new BitmapImage(new Uri("Resource/Image/k1.png", UriKind.Relative));
            toolboxButton.Visibility = System.Windows.Visibility.Collapsed;
            layer0Grid.ColumnDefinitions.Add(_cloneToolboxGrid);

            if (solutionButton.Visibility == System.Windows.Visibility.Collapsed)
                toolboxLayerGrid.ColumnDefinitions.Add(_cloneToToolboxLayerGrid);
        }
        else
        {
            toolboxImage.Source = new BitmapImage(new Uri("Resource/Image/k1.png", UriKind.Relative));
            toolboxButton.Visibility = System.Windows.Visibility.Visible;
            toolboxLayerGrid.Visibility = System.Windows.Visibility.Collapsed;
            layer0Grid.ColumnDefinitions.Remove(_cloneToolboxGrid);

            if (solutionButton.Visibility == System.Windows.Visibility.Collapsed)
                toolboxLayerGrid.ColumnDefinitions.Remove(_cloneToToolboxLayerGrid);
        }
    }

    private void solutionLayerPinButton_Click(object sender, RoutedEventArgs e)
    {
        if (solutionButton.Visibility == System.Windows.Visibility.Visible)
        {
            solutionImage.Source = new BitmapImage(new Uri("Resource/Image/k1.png", UriKind.Relative));
            solutionButton.Visibility = System.Windows.Visibility.Collapsed;
            layer0Grid.ColumnDefinitions.Add(_cloneSolutionGrid);

            if (toolboxButton.Visibility == System.Windows.Visibility.Collapsed)
                toolboxLayerGrid.ColumnDefinitions.Add(_cloneToToolboxLayerGrid);
        }
        else
        {
            solutionImage.Source = new BitmapImage(new Uri("Resource/Image/k1.png", UriKind.Relative));
            solutionButton.Visibility = System.Windows.Visibility.Visible;
            solutionLayerGrid.Visibility = System.Windows.Visibility.Collapsed;
            layer0Grid.ColumnDefinitions.Remove(_cloneSolutionGrid);

            if (toolboxButton.Visibility == System.Windows.Visibility.Collapsed)
                toolboxLayerGrid.ColumnDefinitions.Remove(_cloneToToolboxLayerGrid);
        }
    }
}

其中layer0Grid.ColumnDefinitions.Add(_cloneToolboxGrid)就是增加6号区域的代码,这里的代码逻辑比较简单,完全是根据布局来的,思路跟6号区域完全一致,这个代码就不再做分析了。

最后来说一下SharedSizeGroup属性。该属性的意思其实就是所有SharedSizeGroup属性值相同的区域拥有相同的大小,大小值为:所有SharedSizeGroup属性相同区域中大小最大的那个区域。

换句话说,若有A和B两个布局,如果他们两个布局的SharedSizeGroup属性相同,都为某值“aaa”(其实“aaa”没有规则,只要符合命名规则就行,你爱叫什么叫什么,只要希望共享size的区域的该名称是一样的就行),则A和B有相同的大小,两个布局谁大就用谁的大小。

所以,这里就可以回答刚刚的一个没有回答的问题,怎么使6号区域与toolboxGrid一样大?现在答案就很简单了,那就是让6号区域和toolboxGrid的SharedSizeGroup属性相同即可,所以layer0Grid.ColumnDefinitions.Add(_cloneToolboxGrid)中会带有 _cloneToolboxGrid参数,这个参数就是toolboxGrid的SharedSizeGroup属性值。

至此,应该差不多把第一个图中演示的实例的实现过程主脉络分析清楚了,剩下的东西就不再分析了。如果有哪里说得不对的,欢迎指正。

相关阅读

分享到:

栏目导航

推荐阅读

热门阅读