Windows 8 Metro 應用開發入門(二):Metro App的幾個新控件


摘 要

基於Silverlight開發Metro App可以使用Silverlight原生的控件,為了更好的開發Metro App,控件庫又專門增加了幾個新的控件,如:GridView、Flipview、ProgressRing、SemanticZoom和VariableSizedWrapGrid等,這些控件為平板設備提供了良好的觸控體驗,這一章我們來介紹一下這幾個控件的簡單用法。

第1節 GridView

GridView是以網格樣式展現一組數據,在Web開發中就已經存在,主要用於多行多列的數據顯示中。Metro中以分組形式表達數據使用GridView更得心應手,在Silverlight 5及以前版本中,如果想實現分組數據展現要先寫一堆數據模板,而在Metro中,這種展現方式得到了增強,GridView 是專門用於分組數據的,如果僅僅是列表數據,則建議使用ListView。

GridView控件有幾個非常重要的常用成員:

(1) 數據源

如果是以分組形式展示數據,則數據源必須是可分組的,也即是有主從關系,通常是主列表項中每一項可能存在着某一子列表。GridView的數據源依托於CollectionViewSource,CollectionViewSource有一個屬性IsSourceGrouped指明數據源是否是分組源數據集合,還有一個屬性ItemsPath指明查找子數據項的路徑,通常將可分組的源數據指定給CollectionViewSource對象的Source屬性,如下定義了年級與學生的主從關系,年級包含了學生的數據列表:

    public class Grade
    {
        public Grade()
        {
            Students = new ObservableCollection<Student>();
        }
        public string Name { get; set; }
        public ObservableCollection<Student> Students { get; private set; }
    }

    public class Student
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
        public bool IsClassLeader { get; set; }
        public string Grade { get; set; }
    }

以下代碼來模擬生成三個年級的學生:

        private List<Grade> CreateGrades()
        {
            List<Grade> Grades = new List<Grade>();
            for (int i = 1; i <= 3; i++)
            {
                Grade grade = new Grade();
                grade.Name = "年級 " + i;
                for (int j = 1; j <= 5; j++)
                {
                    grade.Students.Add(new Student()
                    {
                        Name = "王學生 " + j,
                        IsClassLeader = true,
                        Birthday = startDate.AddDays(j + 1),
                        Grade = grade.Name
                    });
                }
                Grades.Add(grade);
            }
            //MyGrades.Source = Grades;
            return Grades;
        }

那么,對於這個方法生成的數據源即是可分組的。對於CollectionViewSource,既可以使用靜態資源的形式綁定到視圖,也可以以后台代碼的形式綁定。

(2)使用GridView展示數據源

a)、項樣式

如果要展示個性化的數據視圖,需要自定義DataTemplate來規划每組下的每個數據項的布局,如下是對每個學生信息的展示布局:

            <GridView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="20">
                        <TextBlock Text="{Binding Name}" FontWeight="Bold" Style="{StaticResource ItemTextStyle}"/>
                        <TextBlock Text="{Binding Birthday}" TextWrapping="NoWrap" Style="{StaticResource BodyTextStyle}" />
                        <CheckBox Content="班干部" IsChecked="{Binding IsClassLeader}" IsEnabled="False"/>
                    </StackPanel>
                </DataTemplate>
            </GridView.ItemTemplate>

b)、組樣式

也可以對每個分組的展示布局及樣式自定義,通過GroupStyle進行設定,如下是對每個年級分組的樣式定義:

            <GridView.GroupStyle>
                <GroupStyle HidesIfEmpty="False">
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Background="Yellow" Margin="0">
                                <TextBlock Text="{Binding Name}" Foreground="Black" Margin="30" Style="{StaticResource HeaderTextStyle}"/>
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="GroupItem">
                            <Setter Property="MinWidth" Value="300"/>
                            <Setter Property="BorderBrush" Value="Blue"/>
                            <Setter Property="BorderThickness" Value="2"/>
                            <Setter Property="Margin" Value="3,0"/>
                            <Setter Property="Background" Value="Silver"/>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </GridView.GroupStyle>

HidesIfEmpty屬性指定當子項為空時是否隱藏組。

HeaderTemplate 定義組頭樣式。

效果圖:

c)、選定項事件

當選定項改變時觸發事件SelectionChanged,與Listview、DropDownlist等控件的效果差不多,在事件處理程序中可以做相應處理,如下:

        private void GridView_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
        {
            Student student = ((GridView)sender).SelectedItem as Student;
            Debug.WriteLine(student.Name);
        }

以下是完整的示例代碼:

XAML:

View Code
    <Page.Resources>
        <CollectionViewSource x:Name="MyStudents" IsSourceGrouped="True"/>
    </Page.Resources>
<GridView MaxHeight="500" Margin="0,120,0,0" Grid.Column="1"  ItemsSource="{Binding Source={StaticResource MyGrades}}" SelectionChanged="GridView_SelectionChanged_1" >
            <GridView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="20">
                        <TextBlock Text="{Binding Name}" FontWeight="Bold" Style="{StaticResource ItemTextStyle}" Foreground="Purple"/>
                        <TextBlock Text="{Binding Birthday}" TextWrapping="NoWrap" Style="{StaticResource BodyTextStyle}" />
                        <CheckBox Content="班干部" IsChecked="{Binding IsClassLeader}" IsEnabled="False"/>
                    </StackPanel>
                </DataTemplate>
            </GridView.ItemTemplate>
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>

            <GridView.GroupStyle>
                <GroupStyle HidesIfEmpty="False">
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Background="Yellow" Margin="0">
                                <TextBlock Text="{Binding Name}" Foreground="Black" Margin="30" Style="{StaticResource HeaderTextStyle}"/>
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="GroupItem">
                            <Setter Property="MinWidth" Value="300"/>
                            <Setter Property="BorderBrush" Value="Blue"/>
                            <Setter Property="BorderThickness" Value="2"/>
                            <Setter Property="Margin" Value="3,0"/>
                            <Setter Property="Background" Value="Silver"/>
                        </Style>
                    </GroupStyle.ContainerStyle>

                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            <VariableSizedWrapGrid/>
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </GridView.GroupStyle>
        </GridView>

C# 綁定數據:

        private List<Grade> CreateGrades()
        {
            List<Grade> Grades = new List<Grade>();
            for (int i = 1; i <= 3; i++)
            {
                Grade grade = new Grade();
                grade.Name = "年級 " + i;
                for (int j = 1; j <= 5; j++)
                {
                    grade.Students.Add(new Student()
                    {
                        Name = "王學生 " + j,
                        IsClassLeader = true,
                        Birthday = startDate.AddDays(j + 1),
                        Grade = grade.Name
                    });
                }
                Grades.Add(grade);
            }
            MyGrades.Source = Grades;
            return Grades;
        }

在基於橫向排列分組時建議使用GridView,在基於縱向排列分組時建議使用ListView,關於ListView的使用請參考相關文檔,這里不再介紹。下面給一個ListView的分組效果圖:

 

第2節 Flipview

Flipview允許基於“上一頁”“下一頁”的方式瀏覽一系列視圖,視圖可以是圖片,也可以是其他的自定義布局。現在很多網站上都有對圖片的類似瀏覽方式,如網易的圖片新聞,上一頁的導航在整個視圖的左側,下一頁的導航在右側,這種導航非常適合在觸摸設備中使用。如下:

Flipview控件來源於ItemsControl,它的使用比較簡單,類似於一個容器,只需要往里塞視圖即可,至於如何處理上下頁的翻轉,內部都已經完全實現好了,不僅可以往里面旋轉圖片,還可以放置其他的視圖。如下:

                <FlipView HorizontalAlignment="Left" SelectionChanged="FlipView_SelectionChanged_1"  Margin="12"
 VerticalAlignment="Top" Grid.Row="1" Width="500">
            <Image Source="Assets/bg0.jpg" />
            <Image Source="Assets/bg1.jpg" />
            <Image Source="Assets/bg2.jpg" />
            <Image Source="Assets/bg3.jpg" />
            <Image Source="Assets/bg4.jpg" />
            <Grid>
                <TextBlock Text="12312313" FontSize="30"/>
            </Grid>
        </FlipView>

Image可以與Grid共存。Flipview同樣有SelectionChanged事件,在事件處理程序中可以獲取導航到當前的視圖項。

 

第3節 ProgressRing

在Windows 8 中有一個新的進度條,就是幾個點圍繞一個圓旋轉(當用戶登錄到Windows8系統時可以看到)。Metro應用程序也提供了這一效果的控件。如下:

它的使用非常的簡單:

<ProgressRing x:Name="pr" Grid.Row="1" HorizontalAlignment="Left" Margin="500,231,0,0" 
VerticalAlignment="Top" Height="108" Width="108" IsActive="True"/>

它有一個很重要的屬性IsActive來控制它的活動與休眠。

 

第4節 SemanticZoom

SemanticZoom控件提供了同一個數據源兩種視圖的展現形式,這是一個很有意思的控件,也可以說一個是近景視圖ZoomedInView一個是遠景視圖ZoomedOutView,我們暫且稱它人近景、遠景吧。在近景視圖中可以瀏覽每個項的詳細信息,遠景視圖類似預覽圖,一般是瀏覽項的簡略數據,如下分別是視圖ZoomedInView和視圖ZoomedOutView:

注意看視圖ZoomedInView的右下角有個紅圈圍起來的一個“一”字按鈕,點它可以切換到遠景視圖,當點擊遠景視圖中的一個項時又切換回近景視圖。這通常在快速預覽數據列表時很有用,可以向用戶隱藏一些不必要的數據。

SemanticZoom有兩個非常重要的屬性ZoomedInView和ZoomedOutView,當向這兩個視圖提供布局時該控件才可進行近遠景視圖的切換。如下:

<SemanticZoom HorizontalAlignment="Left" Margin="10" Grid.Row="1" VerticalAlignment="Top">
            <SemanticZoom.ZoomedInView>
                <GridView x:Name="gv1" ScrollViewer.IsHorizontalScrollChainingEnabled="False" ScrollViewer.IsVerticalScrollChainingEnabled="False">
                    <GridView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="20">
                                <TextBlock Text="{Binding Name}" FontWeight="Bold" Style="{StaticResource ItemTextStyle}"/>
                                <TextBlock Text="{Binding DueDate}" TextWrapping="NoWrap" Style="{StaticResource BodyTextStyle}" />
                                <CheckBox Content="Complete" IsChecked="{Binding Complete}" IsEnabled="False"/>
                            </StackPanel>
                        </DataTemplate>
                    </GridView.ItemTemplate>
                </GridView>
            </SemanticZoom.ZoomedInView>
            <SemanticZoom.ZoomedOutView>
                <GridView x:Name="gv2" ScrollViewer.IsHorizontalScrollChainingEnabled="False" ScrollViewer.IsVerticalScrollChainingEnabled="False">
                    <GridView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="20">
                                <TextBlock Text="{Binding Name}" Width="100" FontWeight="Bold" Foreground="Red" Style="{StaticResource ItemTextStyle}" FontSize="26"/>
                            </StackPanel>
                        </DataTemplate>
                    </GridView.ItemTemplate>
                </GridView>
            </SemanticZoom.ZoomedOutView>
        </SemanticZoom>

bool CanChangeViews 指明是否可以進行視圖切換

bool IsZoomedInViewActive 指明近景視圖ZoomedInView是否為活動視圖

在視圖切換時會觸發兩個事件:ViewChangeStarted和ViewChangeCompleted。

代碼:

        public class SemanticItem
        {
            public string Name { get; set; }
            public DateTime DueDate { get; set; }
            public bool Complete { get; set; }
        }
        private void InitDataSource()
        {
            List<SemanticItem> ds = new List<SemanticItem>();
            for (int i = 0; i < 20; i++)
            {
                ds.Add(new SemanticItem() { Name = "S " + i, DueDate = DateTime.Now, Complete = true });
            }
            this.gv1.ItemsSource = this.gv2.ItemsSource = ds;
        }

如果你想向用戶提供兩個非常修改化的視圖,當然可以發揮你的豐富想象力來實現布局。

 

第5節 VariableSizedWrapGrid

在Silverlight/WPF有一個擴展控件WrapPanel,它是根據自身的寬高和子元素的寬高對子元素進行“換行”排列,當指定子元素橫排列優先時,如果橫向布局不足容納全部子元素,則會自動從下一行開始排列,縱向排列優先時類似。Metro應用提供了一個類似的控件VariableSizedWrapGrid,它比WrapPanel有更多的控制,比如,它可以指定子元素的寬和高,還可以指定當前用於布局子元素的行和列數,並且它還能指定某個子元素占用幾行或幾列,非常強大!如下圖:

XAML:

<VariableSizedWrapGrid Grid.Row="1" MaximumRowsOrColumns="5" ItemHeight="44" ItemWidth="44" HorizontalAlignment="Left"
 Height="262" Margin="10,10,0,0" VerticalAlignment="Top" Width="396">
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="Red"/>
            <Rectangle Fill="Blue"/>
            <Rectangle Fill="White" Height="80" VariableSizedWrapGrid.RowSpan="2"/>
            <Rectangle Fill="Green" Width="80" VariableSizedWrapGrid.ColumnSpan="2"/>

        </VariableSizedWrapGrid>

VariableSizedWrapGrid有幾個非常重要的屬性:

double ItemHeight 設置每個子項的高

double ItemWidth 設置每個子項的寬

Orientation Orientation 子元素的排列方向

int MaximumRowsOrColumns獲取或設置影響換行點同時說明 Orientation 的值。

DependencyProperty RowSpanProperty 子元素占據的行數,如上圖中的白色塊。

DependencyProperty ColumnSpanProperty 子元素占據的列數,如上圖中的綠色塊。

 

小 結

這一章簡單介紹了5個控件的常用方法,其實有過Silverlight/WPF經驗的都很容易理解,也參考MSDN的相關文檔。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM