不知道有人注意過Win10中的設置頁面的布局沒?那個頁面會根據不同的窗口寬度來調節顯示的內容,甚至來后退按鈕的操作在不同的寬度也是不同的,看圖:
是不是有點cool呢,這篇文章,我們就來做一個類似的布局。
首先將我們需要展示出來的東西都添加到頁面上,頁面如下:
1 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 2 <Grid.RowDefinitions> 3 <RowDefinition Height="30"></RowDefinition> 4 <RowDefinition Height="*"></RowDefinition> 5 </Grid.RowDefinitions> 6 7 <!--大標題,后退按鈕--> 8 <StackPanel Grid.Row="0" Orientation="Horizontal" x:Name="fullPanel"> 9 <Button Content="Back" x:Name="full_back" Click="full_back_Click"></Button> 10 <TextBlock Margin="10, 0, 0, 0">這是一個大標題</TextBlock> 11 </StackPanel> 12 13 14 <!--副標題,后退按鈕,只在desktop上寬度小於500時顯示--> 15 <StackPanel Grid.Row="0" Orientation="Horizontal" x:Name="detailPanel" > 16 <Button x:Name="detail_back" Content="Back" Click="detail_back_Click"></Button> 17 <TextBlock Margin="10, 0, 0, 0">這是一個副標題</TextBlock> 18 </StackPanel> 19 20 <!--內容--> 21 <RelativePanel Grid.Row="1"> 22 <!--左半部分的list--> 23 <ListView x:Name="left" IsItemClickEnabled="True" ItemClick="left_ItemClick" SelectedIndex="-1"> 24 <ListView.ItemTemplate> 25 <DataTemplate> 26 <StackPanel Margin="10"> 27 <TextBlock> 28 <Run Text="Item: "></Run> 29 <Run Text="{Binding}"></Run> 30 </TextBlock> 31 </StackPanel> 32 </DataTemplate> 33 </ListView.ItemTemplate> 34 </ListView> 35 36 <!--右半部份的詳細信息--> 37 <Grid x:Name="right" > 38 <StackPanel> 39 <TextBlock>隊長,別開槍。。</TextBlock> 40 <TextBlock > 41 <Run Text="Item:"></Run> 42 <Run Text="{Binding SelectedItem, ElementName=left}" Foreground="Red"></Run> 43 </TextBlock> 44 </StackPanel> 45 </Grid> 46 </RelativePanel> 47 </Grid>
后台綁定測試數據:
1 private void MainPage_Loaded(object sender, RoutedEventArgs e) 2 { 3 this.left.ItemsSource = Enumerable.Range(1, 10).ToList(); 4 }
運行起來看看效果,有點亂啊,不急,我們慢慢調。
這個頁面中,我們准備在窗口寬度小於500時顯示窄布局,大於500時顯示寬布局,下面就是我們的VisualState發揮作用的時候了。我們先創建一個VisualStateGroup,只用來針對窗口大小來調整布局,暫時先忽略掉mobile,詳細說明請看注釋。
1 <VisualStateManager.VisualStateGroups> 2 <!--這個group里的VisualState只針對窗口寬度調整布局,不涉及設備--> 3 <VisualStateGroup x:Name="windowSize"> 4 <!--寬屏設置--> 5 <VisualState x:Name="wide"> 6 <VisualState.StateTriggers> 7 <!--大於等於501就算寬屏了。。--> 8 <AdaptiveTrigger MinWindowWidth="501"></AdaptiveTrigger> 9 </VisualState.StateTriggers> 10 <VisualState.Setters> 11 <!--這里進行寬屏下的設置--> 12 <!--隱藏副標題--> 13 <Setter Target="detailPanel.Visibility" Value="Collapsed"></Setter> 14 15 <!--顯示大標題,雖然大標題默認是顯示的,但是因為我們以后會通過code修改顯示屬性,所以這里要重置才行--> 16 <Setter Target="fullPanel.Visibility" Value="Visible"></Setter> 17 18 <!--顯示右側內容--> 19 <Setter Target="right.Visibility" Value="Visible"></Setter> 20 21 <!--寬屏時,右側內容應該是在list的右側--> 22 <Setter Target="right.(RelativePanel.RightOf)" Value="left"></Setter> 23 24 <!--顯示左側內容--> 25 <Setter Target="left.Visibility" Value="Visible"></Setter> 26 </VisualState.Setters> 27 </VisualState> 28 29 <!--窄屏設置--> 30 <VisualState x:Name="narrow"> 31 <VisualState.StateTriggers> 32 <!--0-500都是小窗口--> 33 <AdaptiveTrigger MinWindowWidth="0"></AdaptiveTrigger> 34 35 </VisualState.StateTriggers> 36 <VisualState.Setters> 37 <!--默認顯示副標題--> 38 <Setter Target="detailPanel.Visibility" Value="Visible"></Setter> 39 40 <!--隱藏大標題,點擊副標題的后退才顯示--> 41 <Setter Target="fullPanel.Visibility" Value="Collapsed"></Setter> 42 43 <!--顯示右側內容,點擊副標題后退之后隱藏--> 44 <Setter Target="right.Visibility" Value="Visible"></Setter> 45 46 <!--隱藏左側內容--> 47 <Setter Target="left.Visibility" Value="Collapsed"></Setter> 48 </VisualState.Setters> 49 </VisualState> 50 </VisualStateGroup> 51 </VisualStateManager.VisualStateGroups>
運行起來看看是不是效果要好很多了呢,現在調整窗口的寬度,是不是有點意思了呢?
但是后退按鈕還是沒有效果,這里我們需要使用code去控制了,但是這個很簡單,因為我們在不同的布局下,使用的是不同的button,這樣的好處是不需要用code去判斷窗口狀態。這里我們只貼上后台代碼,同樣很簡單。
1 private void full_back_Click(object sender, RoutedEventArgs e) 2 { 3 // 對於我們的頁面來說,full_back按鈕是應該隱藏的,因為沒有上一層頁面 4 // 所以這里我們忽略掉,但是按鈕還是留着,你可以自己來做個隱藏的邏輯 5 } 6 7 private void detail_back_Click(object sender, RoutedEventArgs e) 8 { 9 // 這里就是為什么我們在VisualState里重新設置屬性的原因 10 11 // 顯示左側的list 12 // 隱藏右側內容 13 this.left.Visibility = Visibility.Visible; 14 this.right.Visibility = Visibility.Collapsed; 15 16 // 隱藏副標題 17 // 顯示主標題 18 this.fullPanel.Visibility = Visibility.Visible; 19 this.detailPanel.Visibility = Visibility.Collapsed; 20 } 21 22 private void left_ItemClick(object sender, ItemClickEventArgs e) 23 { 24 // 這里我們需要判斷下,是否需要切換隱藏 25 if (this.ActualWidth <= 500) 26 { 27 // 顯示左側的list 28 // 隱藏右側內容 29 this.left.Visibility = Visibility.Collapsed; 30 this.right.Visibility = Visibility.Visible; 31 32 // 隱藏副標題 33 // 顯示主標題 34 this.fullPanel.Visibility = Visibility.Collapsed; 35 this.detailPanel.Visibility = Visibility.Visible; 36 } 37 }
到這里的話,我們的這個頁面的行為和設置已經有點像了!
到這里我們這個頁面的基本功能就算是差不多了,然后來完善下細節(其實還是有個小問題,狀態的切換還是和設置有些區別的)。
1. 窗口寬度大於500的時候,直接給他一個固定的寬度,讓list能寬一些。
2. 窗口寬度小於500的時候,把list撐滿整個頁面。這里我們需要說下RelativePanel的一個特性(應該是特性吧。。),它內部的控件是不會自動拉伸撐滿內部空間的,即使你用了HorizontalAlignment/VerticalAlignment,連Grid都不行!!我們需要使用RelativePanel.AlignXXXX這一系列屬性,根據需要來拉伸。
在我們的頁面中,我們需要在窄屏下上下左右都對齊,來撐滿頁面。
1 <!--拉伸左側list,撐滿頁面--> 2 <Setter Target="left.(RelativePanel.AlignRightWithPanel)" Value="True"></Setter> 3 <Setter Target="left.(RelativePanel.AlignBottomWithPanel)" Value="True"></Setter> 4 <Setter Target="left.(RelativePanel.AlignLeftWithPanel)" Value="True"></Setter> 5 <Setter Target="left.(RelativePanel.AlignTopWithPanel)" Value="True"></Setter>
最后的效果!
這篇文章的例子只是一個很簡單布局,如果你准備實現復雜一些的功能的話,可以考慮把右側的Grid換成Frame,然后通過左側的ListItem導航到不同的頁面,來顯示不同的內容。