介紹
重新想象 Windows 8 Store Apps 之 SemanticZoom
演示 SemanticZoom 的應用
通過 ISemanticZoomInformation 接口實現自定義 SemanticZoom 的 View
示例
1、演示 SemanticZoom 的應用
Index.xaml
<Page
x:Class="XamlDemo.Index"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="Transparent">
<SemanticZoom x:Name="semanticZoom" HorizontalAlignment="Left">
<!--
放大後的視圖,詳細數據
-->
<SemanticZoom.ZoomedInView>
<GridView x:Name="gridViewDetails" SelectionMode="None" IsSwipeEnabled="false" Padding="120 0 0 0">
<!--分組後,details 的數據模板-->
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="#022a56" Width="200" Height="65" Tapped="Grid_Tapped_1" Tag="{Binding}">
<TextBlock TextWrapping="Wrap" FontSize="14.667" Foreground="#ffffff" Padding="5 0"
HorizontalAlignment="Left" VerticalAlignment="Center"
Text="{Binding Title}"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<!--分組的樣式-->
<GridView.GroupStyle>
<GroupStyle>
<!--分組後,header 的數據模板-->
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" FontSize="26.67" Height="30" Margin="0 0 0 20" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<!--分組後,每組數據(包括 header 和 details)的樣式-->
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding
Background}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
<!--
每組數據的 details 數據源來自 ICollectionViewGroup.GroupItems
-->
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding GroupItems}" Grid.Row="1"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
<!--分組後,每組數據(包括 header 和 details)的 panel-->
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0 0 50 0" ItemHeight="75" Loaded="VariableSizedWrapGrid_Loaded_1" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
<!--整體數據(一組數據算一個元素)的 panel-->
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</SemanticZoom.ZoomedInView>
<!--
縮小後的視圖,概述數據
-->
<SemanticZoom.ZoomedOutView>
<GridView Name="gridViewSummary" HorizontalAlignment="Left" Padding="120 0 0 0">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="#022a56" Width="100" Height="100">
<!--
每組數據的 header 數據源來自 ICollectionViewGroup.Group
-->
<TextBlock Text="{Binding Group.Title}" Foreground="#ffffff" Opacity="0.9" FontSize="14.667" Margin="5" TextAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" TextWrapping="Wrap" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="8" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="5 5 5 30" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
</GridView.ItemContainerStyle>
</GridView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
</Grid>
</Page>
Index.xaml.cs
/*
* 本頁為此 app 的導航頁,同時用於演示:
* 1、ItemsControl 控件如何分組
* 2、SemanticZoom 控件的應用
*
*
* SemanticZoom - 用於關聯兩個有語義關系的視圖
* ZoomedInView - 放大後的視圖,詳細數據
* ZoomedOutView - 縮小後的視圖,概述數據
* IsZoomedInViewActive - ZoomedInView 是否為當前正在顯示的視圖
* CanChangeViews - 是否可在兩個視圖間切換
* IsZoomOutButtonEnabled - 是否顯示用於切換視圖的按鈕
* ToggleActiveView() - 切換視圖
* ViewChangeStarted - 視圖開始切換時觸發的事件
* ViewChangeCompleted - 視圖切換完成時觸發的事件
*
*
* ItemsControl - 一個用於呈現集合數據的控件(GridView, ListView, FlipView, ListBox 等均直接或間接地繼承了 ItemsControl)
* ItemsControl 控件提供了分組功能
*
* CollectionViewSource - 對集合數據啟用分組支持
* Source - 數據源
* View - 獲取視圖對象,返回一個實現了 ICollectionView 接口的對象
* IsSourceGrouped - 數據源是否是一個被分組的數據
* ItemsPath - 數據源中,子數據集合的屬性名稱
*
* ICollectionView - 支持數據分組
* CollectionGroups - 組數據集合
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation;
using XamlDemo.Common;
namespace XamlDemo
{
public sealed partial class Index : Page
{
// 本頁所用到的 GridView 的水平方向上的滾動值
private double _scrollViewerHorizontalOffset = 0;
public Index()
{
this.InitializeComponent();
XElement root = XElement.Load("SiteMap.xml");
var items = LoadData(root);
// 構造數據源
CollectionViewSource groupedNavigationData = new CollectionViewSource();
groupedNavigationData.IsSourceGrouped = true;
groupedNavigationData.Source = items;
groupedNavigationData.ItemsPath = new PropertyPath("Items");
// 綁定數據
gridViewDetails.ItemsSource = groupedNavigationData.View; // 全部數據
gridViewSummary.ItemsSource = groupedNavigationData.View.CollectionGroups; // 關聯的組數據集合
// 必須緩存此頁
this.NavigationCacheMode = NavigationCacheMode.Required;
gridViewDetails.Loaded += gridViewDetails_Loaded;
}
// 導航到其它頁之前,保存本頁所用到的 GridView 的水平方向上的滾動值
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
var scrollViewer = Helper.GetVisualChild<ScrollViewer>(gridViewDetails);
_scrollViewerHorizontalOffset = scrollViewer.HorizontalOffset;
}
// GridView 加載之後,指定其水平方向上的滾動值
void gridViewDetails_Loaded(object sender, RoutedEventArgs e)
{
var scrollViewer = Helper.GetVisualChild<ScrollViewer>(gridViewDetails);
scrollViewer.ScrollToHorizontalOffset(_scrollViewerHorizontalOffset);
}
// 獲取數據
private List<NavigationModel> LoadData(XElement root)
{
if (root == null)
return null;
var items = from n in root.Elements("node")
select new NavigationModel
{
Title = (string)n.Attribute("title"),
Url = (string)n.Attribute("url"),
Items = LoadData(n)
};
return items.ToList();
}
// 導航到指定的 Demo 頁
private void Grid_Tapped_1(object sender, TappedRoutedEventArgs e)
{
var model = (NavigationModel)(sender as Grid).Tag;
MainPage.Current.SubTitle = model.Title;
MainPage.Current.Container.Navigate(Type.GetType(model.Url));
}
// 根據屏幕的 height 調整 VariableSizedWrapGrid 的 MaximumRowsOrColumns
// 本例會自動 wrap ,所以不需要以下邏輯,在需要的場景下可以用之
private void VariableSizedWrapGrid_Loaded_1(object sender, RoutedEventArgs e)
{
/*
var screenHeight = Window.Current.Bounds.Height; // CoreWindow.GetForCurrentThread().Bounds.Height
var vswg = sender as VariableSizedWrapGrid;
vswg.MaximumRowsOrColumns = (int)((screenHeight - 200) / 75);
*/
}
class NavigationModel
{
public string Title { get; set; }
public string Url { get; set; }
public List<NavigationModel> Items { get; set; }
}
}
}
2、演示如何自定義 SemanticZoom 視圖
SemanticZoom/MyFlipView.cs
/*
* 開發一個實現了 ISemanticZoomInformation 接口的自定義 FlipView
*/
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
namespace XamlDemo.Controls.SemanticZoom
{
public class MyFlipView : FlipView, ISemanticZoomInformation
{
public MyFlipView()
: base()
{
}
public void CompleteViewChange() { }
public void CompleteViewChangeFrom(SemanticZoomLocation source, SemanticZoomLocation destination) { }
public void CompleteViewChangeTo(SemanticZoomLocation source, SemanticZoomLocation destination) { }
public void InitializeViewChange() { }
public bool IsActiveView { get; set; }
public bool IsZoomedInView { get; set; }
public Windows.UI.Xaml.Controls.SemanticZoom SemanticZoomOwner { get; set; }
public void StartViewChangeFrom(SemanticZoomLocation source, SemanticZoomLocation destination) { }
/// <summary>
/// ZoomedOutView -> ZoomedInView 時觸發的事件
/// </summary>
/// <param name="source">在 ZoomedOutView 時被選中的數據</param>
/// <param name="destination">需要傳遞給 ZoomedInView 的數據</param>
public void StartViewChangeTo(SemanticZoomLocation source, SemanticZoomLocation destination)
{
/*
* 注:
* GridView 和 ListView 均實現了 ISemanticZoomInformation 接口
* 參見本 app 的關於 SemanticZoom 的 Demo,通過 CollectionViewSource 綁定數據即可使 SemanticZoom 中的兩個視圖進行有關聯地切換
* 此時此處的 source.Item 便為一個 ICollectionViewGroup 類型的數據,其有兩個屬性:Group 和 GroupItems
*/
// 獲取在 ZoomedOutView 中被選中的項,即被選中的父親
NavigationModel model = source.Item as NavigationModel;
// 將此父親的所有子數據傳遞給 ZoomedInView,接下來會執行 MakeVisible() 方法
destination.Item = model.Items;
}
/// <summary>
/// 開始 ZoomedOutView -> ZoomedInView 之後,會調用此方法
/// 一般在此處重整 ZoomedInView 的數據源,或者滾動 ZoomedInView 中的內容到指定的項以對應 ZoomedOutView 中被選中的數據
/// </summary>
/// <param name="item">由 StartViewChangeTo() 方法傳遞給 ZoomedInView 的數據
</param>
public void MakeVisible(SemanticZoomLocation item)
{
// 將 FlipView 的數據源指定為被選中的父親的所有子數據
this.ItemsSource = item.Item;
}
}
}
SemanticZoom/CustomView.xaml
<Page
x:Class="XamlDemo.Controls.SemanticZoom.CustomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Controls.SemanticZoom"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="Transparent">
<SemanticZoom x:Name="semanticZoom" IsZoomedInViewActive="False" Margin="120 0 0 0">
<!--
放大後的視圖,詳細數據
-->
<SemanticZoom.ZoomedInView>
<local:MyFlipView x:Name="flipView" Width="600" Height="300" HorizontalAlignment="Left">
<FlipView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" FontSize="26.667" />
</DataTemplate>
</FlipView.ItemTemplate>
<FlipView.ItemContainerStyle>
<Style TargetType="FlipViewItem">
<Setter Property="Background" Value="Blue" />
</Style>
</FlipView.ItemContainerStyle>
</local:MyFlipView>
</SemanticZoom.ZoomedInView>
<!--
縮小後的視圖,概述數據
-->
<SemanticZoom.ZoomedOutView>
<GridView Name="gridView" HorizontalAlignment="Left">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="#022a56" Width="100" Height="100">
<TextBlock Text="{Binding Title}" Foreground="#ffffff" Opacity="0.9" FontSize="14.667" Margin="5" TextAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" TextWrapping="Wrap" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="8" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="5 5 5 30" />
<Setter Property="HorizontalContentAlignment" Value="Center"
/>
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
</GridView.ItemContainerStyle>
</GridView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
</Grid>
</Page>
SemanticZoom/CustomView.xaml.cs
/*
* 演示如何自定義 SemanticZoom 視圖
* 演示步驟:
* 1、在 ZoomedOutView 視圖中的 GridView 中選中某一項
* 2、展開 ZoomedInView 視圖後,其內的 FlipView 顯示之前被選中項的所有子數據(需要開發一個實現了
ISemanticZoomInformation 接口的自定義 FlipView,參見 MyFlipView.cs)
*
* 注:
* GridView 和 ListView 均實現了 ISemanticZoomInformation 接口,所以可以在 SemanticZoom 的兩個視
圖間有關聯地切換
* 要讓其它控件也實現類似的功能,就必須使其實現 ISemanticZoomInformation 接口
*/
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Windows.UI.Xaml.Controls;
namespace XamlDemo.Controls.SemanticZoom
{
public sealed partial class CustomView : Page
{
public CustomView()
{
this.InitializeComponent();
XElement root = XElement.Load("SiteMap.xml");
var items = LoadData(root);
// 綁定數據
gridView.ItemsSource = items;
}
// 獲取數據
private List<NavigationModel> LoadData(XElement root)
{
if (root == null)
return null;
var items = from n in root.Elements("node")
select new NavigationModel
{
Title = (string)n.Attribute("title"),
Url = (string)n.Attribute("url"),
Items = LoadData(n)
};
return items.ToList();
}
}
public class NavigationModel
{
public string Title { get; set; }
public string Url { get; set; }
public List<NavigationModel> Items { get; set; }
}
}
OK
[源碼下載]:http://files.cnblogs.com/webabcd/Windows8.rar