您的位置:首页 > 移动开发

重新想象 Windows 8.1 Store Apps (93) - 控件增强: GridView, ListView

2015-01-05 15:06 831 查看
[源码下载]

[align=center]重新想象 Windows 8.1 Store Apps (93) - 控件增强: GridView, ListView[/align]

作者:webabcd

介绍
重新想象 Windows 8.1 Store Apps 之控件增强

GridView 和 ListView 每屏显示的数据量多滚动也流畅

GridViewItemPresenter 和 ListViewItemPresenter 更方便更快速地显示各种状态

自定义 GridViewItemPresenter 和 ListViewItemPresenter

示例
1、演示 GridView 和 ListView 的新增特性: GridView 和 ListView 每屏显示的数据量多滚动也流畅
GridViewAndListView/Employee.cs

namespace Windows81.Controls.GridViewAndListView
{
public class Employee
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsMale { get; set; }
}
}


GridViewAndListView/TestData.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Windows81.Controls.GridViewAndListView
{
public class TestData
{
/// <summary>
/// 返回一个 Employee 数据集合,测试用
/// </summary>
public static List<Employee> GetEmployees()
{
var employees = new List<Employee>();

for (int i = 0; i < 10000; i++)
{
employees.Add(
new Employee
{
Name = "Name " + i.ToString().PadLeft(4, '0'),
Age = new Random(i).Next(20, 60),
IsMale = Convert.ToBoolean(i % 2)
});
}

return employees;
}
}
}


GridViewAndListView/IncrementalData.xaml

<Page
x:Name="pageRoot"
x:Class="Windows81.Controls.GridViewAndListView.IncrementalData"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows81.Controls.GridViewAndListView"
xmlns:common="using:Windows81.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="Transparent">

<GridView x:Name="gridView" Margin="120 0 0 0"
ContainerContentChanging="gridView_ContainerContentChanging">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Height="100" Width="100" Background="Blue">
<Rectangle x:Name="placeholderRectangle" Fill="Red" Height="10" Opacity="0" />
<TextBlock x:Name="lblName" Text="{Binding Name}" Foreground="Yellow" />
<TextBlock x:Name="lblAge" Text="{Binding Age}" Foreground="Aqua" />
<TextBlock x:Name="lblIsMale" Text="{Binding IsMale}" Foreground="Gray" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>

</Grid>
</Page>


GridViewAndListView/IncrementalData.xaml.cs

/*
* 演示 GridView 和 ListView 的新增特性
*
* 当 GridView 或 ListView 的一屏需要显示的数据量极大时(一屏的 item 多,且每个 item 中的 element 也多),由于每次滚动时需要绘制当前屏的每个 element,这需要占用大量的 ui 资源,所以就会有一些卡顿
* 为了解决这个问题 win8.1 给出了两种解决方案
* 1、设置 GridView 或 ListView 的 ShowsScrollingPlaceholders 属性为 true(默认值),每次显示 item 时先会显示占位符(application 级的背景色块),然后再绘制内容
* 2、通过 GridView 或 ListView 的 ContainerContentChanging 事件,分步绘制 item 中的 element
*/

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Shapes;

namespace Windows81.Controls.GridViewAndListView
{
public sealed partial class IncrementalData : Page
{
public IncrementalData()
{
this.InitializeComponent();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
gridView.ItemsSource = TestData.GetEmployees();

// 默认值是 true,即为了保证流畅,每次显示 item 时先会显示占位符(application 级的背景色块),然后再绘制内容
// 本例演示 ContainerContentChanging 事件的使用,所以不会用到这个
gridView.ShowsScrollingPlaceholders = false;
}

private void gridView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
// 交由我处理吧
args.Handled = true;

// 第 1 阶段绘制
// args.Phase.ToString(); // 0

StackPanel templateRoot = (StackPanel)args.ItemContainer.ContentTemplateRoot;
Rectangle placeholderRectangle = (Rectangle)templateRoot.FindName("placeholderRectangle");
TextBlock lblName = (TextBlock)templateRoot.FindName("lblName");
TextBlock lblAge = (TextBlock)templateRoot.FindName("lblAge");
TextBlock lblIsMale = (TextBlock)templateRoot.FindName("lblIsMale");

// 显示自定义占位符(也可以不用这个,而是直接显示 item 的背景)
placeholderRectangle.Opacity = 1;

// 除了占位符外,所有 item 全部暂时不绘制
lblName.Opacity = 0;
lblAge.Opacity = 0;
lblIsMale.Opacity = 0;

// 开始下一阶段的绘制
args.RegisterUpdateCallback(ShowName);
}

private void ShowName(ListViewBase sender, ContainerContentChangingEventArgs args)
{
// 第 2 阶段绘制
// args.Phase.ToString(); // 1

Employee employee = (Employee)args.Item;
SelectorItem itemContainer = (SelectorItem)args.ItemContainer;
StackPanel templateRoot = (StackPanel)itemContainer.ContentTemplateRoot;
TextBlock lblName = (TextBlock)templateRoot.FindName("lblName");

// 绘制第 2 阶段的内容
lblName.Text = employee.Name;
lblName.Opacity = 1;

// 开始下一阶段的绘制
args.RegisterUpdateCallback(ShowAge);
}

private void ShowAge(ListViewBase sender, ContainerContentChangingEventArgs args)
{
// 第 3 阶段绘制
// args.Phase.ToString(); // 2

Employee employee = (Employee)args.Item;
SelectorItem itemContainer = (SelectorItem)args.ItemContainer;
StackPanel templateRoot = (StackPanel)itemContainer.ContentTemplateRoot;
TextBlock lblAge = (TextBlock)templateRoot.FindName("lblAge");

// 绘制第 3 阶段的内容
lblAge.Text = employee.Age.ToString();
lblAge.Opacity = 1;

// 开始下一阶段的绘制
args.RegisterUpdateCallback(ShowIsMale);
}

private void ShowIsMale(ListViewBase sender, ContainerContentChangingEventArgs args)
{
// 第 4 阶段绘制
// args.Phase.ToString(); // 3

Employee employee = (Employee)args.Item;
SelectorItem itemContainer = (SelectorItem)args.ItemContainer;
StackPanel templateRoot = (StackPanel)itemContainer.ContentTemplateRoot;
Rectangle placeholderRectangle = (Rectangle)templateRoot.FindName("placeholderRectangle");
TextBlock lblIsMale = (TextBlock)templateRoot.FindName("lblIsMale");

// 绘制第 4 阶段的内容
lblIsMale.Text = employee.IsMale.ToString();
lblIsMale.Opacity = 1;

// 隐藏自定义占位符
placeholderRectangle.Opacity = 0;
}
}
}


2、GridViewItemPresenter 和 ListViewItemPresenter - 用于设置控件的各种状态(win8.1 新引入),比 win8 的方式更方便,且更快(win8 的方式是全部加载完后再显示,win8.1 的此方式是需要的时候才加载)
GridViewAndListView/ItemPresenter.xaml

<Page
x:Class="Windows81.Controls.GridViewAndListView.ItemPresenter"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows81.Controls.GridViewAndListView"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Page.Resources>
<Style x:Key="MyGridViewItemPresenterTemplate" TargetType="GridViewItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<!--
GridViewItemPresenter 和 ListViewItemPresenter - 用于设置控件的各种状态(win8.1 新引入),比 win8 的方式更方便,且更快(win8 的方式是全部加载完后再显示,win8.1 的此方式是需要的时候才加载)
Margin - item 的 margin
SelectionCheckMarkVisualEnabled - 是否显示选中状态的标记
SelectedBorderThickness - 选中状态的边框粗细
SelectedBackground - 选中状态的边框颜色
CheckBrush - 选中状态的图标(本例就是那个小对勾)
...... - 还有好多好多,看文档吧
-->
<GridViewItemPresenter Margin="10" SelectionCheckMarkVisualEnabled="True" SelectedBorderThickness="3" SelectedBackground="Red" CheckBrush="{ThemeResource ListViewItemCheckThemeBrush}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>

<Grid Background="Transparent">
<GridView x:Name="gridView" Margin="120 0 0 0"
ItemContainerStyle="{StaticResource MyGridViewItemPresenterTemplate}"
SelectionMode="Multiple">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Height="100" Width="100" Background="Blue">
<TextBlock x:Name="lblName" Text="{Binding Name}" Foreground="Yellow" />
<TextBlock x:Name="lblAge" Text="{Binding Age}" Foreground="Aqua" />
<TextBlock x:Name="lblIsMale" Text="{Binding IsMale}" Foreground="Gray" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
</Page>


GridViewAndListView/ItemPresenter.xaml.cs

/*
* GridViewItemPresenter 和 ListViewItemPresenter - 用于设置控件的各种状态(win8.1 新引入),比 win8 的方式更方便,且更快(win8 的方式是全部加载完后再显示,win8.1 的此方式是需要的时候才加载)
*/

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Windows81.Controls.GridViewAndListView
{
public sealed partial class ItemPresenter : Page
{
public ItemPresenter()
{
this.InitializeComponent();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
gridView.ItemsSource = TestData.GetEmployees();
}
}
}


3、演示自定义 GridViewItemPresenter 和 ListViewItemPresenter 的使用
GridViewAndListView/MyItemPresenter.cs

/*
* 自定义 GridViewItemPresenter 和 ListViewItemPresenter
*
* 本例演示如何自定义一个 ContentPresenter 类,以用于 GridView(参见:ItemPresenterCustom.xaml)
*/

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Shapes;

namespace Windows81.Controls.GridViewAndListView
{
class MyItemPresenter : ContentPresenter
{
Grid _contentGrid = null; // item 的 grid(数据模板中的 Grid,也就是说要使用本例的这个 ContentPresenter 则数据模板中必须要用 Grid 做容器)
Rectangle _pointerOverBorder = null; // 鼠标经过
Rectangle _focusVisual = null; // 选中

PointerDownThemeAnimation _pointerDownAnimation = null;
Storyboard _pointerDownStoryboard = null;

GridView _parentGridView;

public MyItemPresenter()
: base()
{
base.Margin = new Thickness(10);
}

protected override void OnApplyTemplate()
{
base.OnApplyTemplate();

var obj = VisualTreeHelper.GetParent(this);
while (!(obj is GridView))
{
obj = VisualTreeHelper.GetParent(obj);
}
_parentGridView = (GridView)obj;

_contentGrid = (Grid)VisualTreeHelper.GetChild(this, 0);
}

protected override bool GoToElementStateCore(string stateName, bool useTransitions)
{
base.GoToElementStateCore(stateName, useTransitions);

switch (stateName)
{
// 正常状态
case "Normal":
HidePointerOverVisuals();
HideFocusVisuals();
if (useTransitions)
{
StopPointerDownAnimation();
}
break;

// 选中状态
case "Focused":
case "PointerFocused":
ShowFocusVisuals();
break;

// 取消选中状态
case "Unfocused":
HideFocusVisuals();
break;

// 鼠标经过状态
case "PointerOver":
ShowPointerOverVisuals();
if (useTransitions)
{
StopPointerDownAnimation();
}
break;

// 鼠标点击状态
case "Pressed":
case "PointerOverPressed":
if (useTransitions)
{
StartPointerDownAnimation();
}
break;

default: break;
}

return true;
}

private void StartPointerDownAnimation()
{
if (_pointerDownStoryboard == null)
CreatePointerDownStoryboard();

_pointerDownStoryboard.Begin();
}

private void StopPointerDownAnimation()
{
if (_pointerDownStoryboard != null)
_pointerDownStoryboard.Stop();
}

private void ShowFocusVisuals()
{
if (!FocusElementsAreCreated())
CreateFocusElements();

_focusVisual.Opacity = 1;
}

private void HideFocusVisuals()
{
if (FocusElementsAreCreated())
_focusVisual.Opacity = 0;
}

private void ShowPointerOverVisuals()
{
if (!PointerOverElementsAreCreated())
CreatePointerOverElements();

_pointerOverBorder.Opacity = 1;
}

private void HidePointerOverVisuals()
{
if (PointerOverElementsAreCreated())
_pointerOverBorder.Opacity = 0;
}

private void CreatePointerDownStoryboard()
{
_pointerDownAnimation = new PointerDownThemeAnimation();
Storyboard.SetTarget(_pointerDownAnimation, _contentGrid);

_pointerDownStoryboard = new Storyboard();
_pointerDownStoryboard.Children.Add(_pointerDownAnimation);
}

private void CreatePointerOverElements()
{
_pointerOverBorder = new Rectangle();
_pointerOverBorder.IsHitTestVisible = false;
_pointerOverBorder.Opacity = 0;
_pointerOverBorder.Fill = (SolidColorBrush)_parentGridView.Resources["PointerOverBrush"]; // 此资源要预先在 GridView 中定义

_contentGrid.Children.Insert(_contentGrid.Children.Count, _pointerOverBorder);
}

private void CreateFocusElements()
{
_focusVisual = new Rectangle();
_focusVisual.IsHitTestVisible = false;
_focusVisual.Height = 10;
_focusVisual.StrokeThickness = 2;
_focusVisual.VerticalAlignment = VerticalAlignment.Bottom;
_focusVisual.Fill = (SolidColorBrush)_parentGridView.Resources["FocusBrush"]; // 此资源要预先在 GridView 中定义
_focusVisual.Stroke = (SolidColorBrush)_parentGridView.Resources["FocusBrush"]; // 此资源要预先在 GridView 中定义

_contentGrid.Children.Insert(0, _focusVisual);
}

private bool FocusElementsAreCreated()
{
return _focusVisual != null;
}

private bool PointerOverElementsAreCreated()
{
return _pointerOverBorder != null;
}
}
}


GridViewAndListView/ItemPresenterCustom.xaml

<Page
x:Class="Windows81.Controls.GridViewAndListView.ItemPresenterCustom"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows81.Controls.GridViewAndListView"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Page.Resources>
<Style x:Key="MyGridViewItemPresenterTemplate" TargetType="GridViewItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<!--
自定义 GridViewItemPresenter 和 ListViewItemPresenter
关于 GridViewItemPresenter 和 ListViewItemPresenter 的说明参见:ItemPresenter.xaml

MyItemPresenter 参见 MyItemPresenter.cs
-->
<local:MyItemPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>

<Grid Background="Transparent">
<GridView x:Name="gridView" Margin="120 0 0 0"
ItemContainerStyle="{StaticResource MyGridViewItemPresenterTemplate}"
SelectionMode="Multiple">
<GridView.Resources>
<!--MyItemPresenter.cs 中需要用到的资源-->
<SolidColorBrush x:Name="PointerOverBrush" Color="#50505050"/>
<SolidColorBrush x:Name="FocusBrush" Color="#ffff0000"/>
</GridView.Resources>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Height="100" Width="100" Background="Blue">
<TextBlock x:Name="lblName" Text="{Binding Name}" Foreground="Yellow" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
</Page>


GridViewAndListView/ItemPresenterCustom.xaml.cs

/*
* 演示自定义 GridViewItemPresenter 和 ListViewItemPresenter 的使用
*
* 关于 GridViewItemPresenter 和 ListViewItemPresenter 的说明参见:ItemPresenter.xaml
*/

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Windows81.Controls.GridViewAndListView
{
public sealed partial class ItemPresenterCustom : Page
{
public ItemPresenterCustom()
{
this.InitializeComponent();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
gridView.ItemsSource = TestData.GetEmployees();
}
}
}


OK
[源码下载]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐