Windows8/Visual Studio 2012 开发笔记(一) VS2012的ApplicationViewState支持问题
Visual Studio 2012针对不同的ViewState在IDE进行了支持。打开Device工具条,选择特定的视图状态,点选Enable State recording后就可以录制动画了,大大增加了开发效率。不过今天在使用Blank Page的时候,发现无论我怎么加ViewStateGroup到第一个Grid中,Enable State recording一直是灰色的,而且ViewState列表中只有一个Base。而由BasicPage模板建立的就没问题。
继承问题?改下继承,问题依旧。无奈查下MSDN,说要包含一个ApplicationViewStates的Group。ApplicationViewStates是个枚举,不能XAML到Page中,这什么意思啊。最后老方法,把BasicPage中的代码拷了过来,竟然好了。我靠为啥?仔细看看,代码如下:
<VisualStateManager.VisualStateGroups><!-- Visual states reflect the application's view state --><VisualStateGroup x:Name="ApplicationViewStates"><VisualState x:Name="FullScreenLandscape"/><VisualState x:Name="Filled"/><VisualState x:Name="FullScreenPortrait"/><VisualState x:Name="Snapped"/> </VisualStateGroup></VisualStateManager.VisualStateGroups>
突然发现看到“ApplicationViewStates”了,原来是要命名。你妹啊,这文档写得(英文写的也模糊)。尝试改下名字,问题重现。确认是名称问题。
总结:VS2012的视图状态录制功能要求在XAML中增加一个命名为ApplicationViewState的ViewStateGroup,否则该功能无法开启。
注意: 工程的page 一定要从以下LayoutAwarePage 继承
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace SDKTemplate.Common
{
/// <summary>
/// Typical implementation of Page that provides several important conveniences:
/// application view state to visual state mapping, GoBack and GoHome event handlers, and
/// a default view model.
/// </summary>
[Windows.Foundation.Metadata.WebHostHidden]
public class LayoutAwarePage : Page
{
/// <summary>
/// Identifies the <see cref="DefaultViewModel"/> dependency property.
/// </summary>
public static readonly DependencyProperty DefaultViewModelProperty =
DependencyProperty.Register("DefaultViewModel", typeof(IObservableMap<String, Object>),
typeof(LayoutAwarePage), null);
private List<Control> _layoutAwareControls;
/// <summary>
/// Initializes a new instance of the <see cref="LayoutAwarePage"/> class.
/// </summary>
public LayoutAwarePage()
{
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled) return;
// Create an empty default view model
this.DefaultViewModel = new ObservableDictionary<String, Object>();
// Map application view state to visual state for this page when it is part of the visual tree
this.Loaded += this.StartLayoutUpdates;
this.Unloaded += this.StopLayoutUpdates;
}
/// <summary>
/// An implementation of <see cref="IObservableMap<String, Object>"/> designed to be
/// used as a trivial view model.
/// </summary>
protected IObservableMap<String, Object> DefaultViewModel
{
get
{
return this.GetValue(DefaultViewModelProperty) as IObservableMap<String, Object>;
}
set
{
this.SetValue(DefaultViewModelProperty, value);
}
}
/// <summary>
/// Invoked as an event handler to navigate backward in the page's associated
/// <see cref="Frame"/> until it reaches the top of the navigation stack.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
protected virtual void GoHome(object sender, RoutedEventArgs e)
{
// Use the navigation frame to return to the topmost page
if (this.Frame != null)
{
while (this.Frame.CanGoBack) this.Frame.GoBack();
}
}
/// <summary>
/// Invoked as an event handler to navigate backward in the page's associated
/// <see cref="Frame"/> to go back one step on the navigation stack.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the
/// event.</param>
protected virtual void GoBack(object sender, RoutedEventArgs e)
{
// Use the navigation frame to return to the previous page
if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
}
/// <summary>
/// Invoked as an event handler, typically on the <see cref="Loaded"/> event of a
/// <see cref="Control"/> within the page, to indicate that the sender should start
/// receiving visual state management changes that correspond to application view state
/// changes.
/// </summary>
/// <param name="sender">Instance of <see cref="Control"/> that supports visual state
/// management corresponding to view states.</param>
/// <param name="e">Event data that describes how the request was made.</param>
/// <remarks>The current view state will immediately be used to set the corresponding
/// visual state when layout updates are requested. A corresponding
/// <see cref="Unloaded"/> event handler connected to <see cref="StopLayoutUpdates"/>
/// is strongly encouraged. Instances of <see cref="LayoutAwarePage"/> automatically
/// invoke these handlers in their Loaded and Unloaded events.</remarks>
/// <seealso cref="DetermineVisualState"/>
/// <seealso cref="InvalidateVisualState"/>
public void StartLayoutUpdates(object sender, RoutedEventArgs e)
{
var control = sender as Control;
if (control == null) return;
if (this._layoutAwareControls == null)
{
// Start listening to view state changes when there are controls interested in updates
Window.Current.SizeChanged += this.WindowSizeChanged;
this._layoutAwareControls = new List<Control>();
}
this._layoutAwareControls.Add(control);
// Set the initial visual state of the control
VisualStateManager.GoToState(control, DetermineVisualState(ApplicationView.Value), false);
}
private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
this.InvalidateVisualState();
}
/// <summary>
/// Invoked as an event handler, typically on the <see cref="Unloaded"/> event of a
/// <see cref="Control"/>, to indicate that the sender should start receiving visual
/// state management changes that correspond to application view state changes.
/// </summary>
/// <param name="sender">Instance of <see cref="Control"/> that supports visual state
/// management corresponding to view states.</param>
/// <param name="e">Event data that describes how the request was made.</param>
/// <remarks>The current view state will immediately be used to set the corresponding
/// visual state when layout updates are requested.</remarks>
/// <seealso cref="StartLayoutUpdates"/>
public void StopLayoutUpdates(object sender, RoutedEventArgs e)
{
var control = sender as Control;
if (control == null || this._layoutAwareControls == null) return;
this._layoutAwareControls.Remove(control);
if (this._layoutAwareControls.Count == 0)
{
// Stop listening to view state changes when no controls are interested in updates
this._layoutAwareControls = null;
Window.Current.SizeChanged -= this.WindowSizeChanged;
}
}
/// <summary>
/// Translates <see cref="ApplicationViewState"/> values into strings for visual state
/// management within the page. The default implementation uses the names of enum values.
/// Subclasses may override this method to control the mapping scheme used.
/// </summary>
/// <param name="viewState">View state for which a visual state is desired.</param>
/// <returns>Visual state name used to drive the
/// <see cref="VisualStateManager"/></returns>
/// <seealso cref="InvalidateVisualState"/>
protected virtual string DetermineVisualState(ApplicationViewState viewState)
{
return viewState.ToString();
}
/// <summary>
/// Updates all controls that are listening for visual state changes with the correct
/// visual state.
/// </summary>
/// <remarks>
/// Typically used in conjunction with overriding <see cref="DetermineVisualState"/> to
/// signal that a different value may be returned even though the view state has not
/// changed.
/// </remarks>
public void InvalidateVisualState()
{
if (this._layoutAwareControls != null)
{
string visualState = DetermineVisualState(ApplicationView.Value);
foreach (var layoutAwareControl in this._layoutAwareControls)
{
VisualStateManager.GoToState(layoutAwareControl, visualState, false);
}
}
}
/// <summary>
/// Implementation of IObservableMap that supports reentrancy for use as a default view
/// model.
/// </summary>
private class ObservableDictionary<K, V> : IObservableMap<K, V>
{
private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<K>
{
public ObservableDictionaryChangedEventArgs(CollectionChange change, K key)
{
this.CollectionChange = change;
this.Key = key;
}
public CollectionChange CollectionChange { get; private set; }
public K Key { get; private set; }
}
private Dictionary<K, V> _dictionary = new Dictionary<K, V>();
public event MapChangedEventHandler<K, V> MapChanged;
private void InvokeMapChanged(CollectionChange change, K key)
{
var eventHandler = MapChanged;
if (eventHandler != null)
{
eventHandler(this, new ObservableDictionaryChangedEventArgs(CollectionChange.ItemInserted, key));
}
}
public void Add(K key, V value)
{
this._dictionary.Add(key, value);
this.InvokeMapChanged(CollectionChange.ItemInserted, key);
}
public void Add(KeyValuePair<K, V> item)
{
this.Add(item.Key, item.Value);
}
public bool Remove(K key)
{
if (this._dictionary.Remove(key))
{
this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
return true;
}
return false;
}
public bool Remove(KeyValuePair<K, V> item)
{
V currentValue;
if (this._dictionary.TryGetValue(item.Key, out currentValue) &&
Object.Equals(item.Value, currentValue) && this._dictionary.Remove(item.Key))
{
this.InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
return true;
}
return false;
}
public V this[K key]
{
get
{
return this._dictionary[key];
}
set
{
this._dictionary[key] = value;
this.InvokeMapChanged(CollectionChange.ItemChanged, key);
}
}
public void Clear()
{
var priorKeys = this._dictionary.Keys.ToArray();
this._dictionary.Clear();
foreach (var key in priorKeys)
{
this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
}
}
public ICollection<K> Keys
{
get { return this._dictionary.Keys; }
}
public bool ContainsKey(K key)
{
return this._dictionary.ContainsKey(key);
}
public bool TryGetValue(K key, out V value)
{
return this._dictionary.TryGetValue(key, out value);
}
public ICollection<V> Values
{
get { return this._dictionary.Values; }
}
public bool Contains(KeyValuePair<K, V> item)
{
return this._dictionary.Contains(item);
}
public int Count
{
get { return this._dictionary.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
{
return this._dictionary.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this._dictionary.GetEnumerator();
}
public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
{
int arraySize = array.Length;
foreach (var pair in this._dictionary)
{
if (arrayIndex >= arraySize) break;
array[arrayIndex++] = pair;
}
}
}
}
}
<!--
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
-->
<common:LayoutAwarePage
x:Class="SDKTemplate.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SDKTemplate"
xmlns:common="using:SDKTemplate.Common"
xmlns:sys="using:System"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="RootPage">
<common:LayoutAwarePage.Resources>
<Style x:Key="BaseStatusStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Semilight"/>
<Setter Property="FontSize" Value="14.667"/>
<Setter Property="Margin" Value="0,0,0,5"/>
</Style>
<Style x:Key="StatusStyle" BasedOn="{StaticResource BaseStatusStyle}" TargetType="TextBlock">
<Setter Property="Foreground" Value="Green"/>
</Style>
<Style x:Key="ErrorStyle" BasedOn="{StaticResource BaseStatusStyle}" TargetType="TextBlock">
<Setter Property="Foreground" Value="Blue"/>
</Style>
</common:LayoutAwarePage.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="ContentRoot" Background="{StaticResource ApplicationPageBackgroundThemeBrush}" Margin="100,20,100,20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<StackPanel Orientation="Horizontal" Grid.Row="0">
<Image x:Name="WindowsLogo" Stretch="None" Source="Assets/windows-sdk.png" AutomationProperties.Name="Windows Logo" HorizontalAlignment="Left" Grid.Column="0"/>
<TextBlock Text="Windows 8 SDK Samples" VerticalAlignment="Bottom" Style="{StaticResource TitleTextStyle}" TextWrapping="Wrap" Grid.Column="1"/>
</StackPanel>
<ScrollViewer x:Name="MainScrollViewer" Grid.Row="1" ZoomMode="Disabled" IsTabStop="False" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Padding="0,0,0,20" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="FeatureName" Grid.Row="0" Text="Add Sample Title Here" Style="{StaticResource HeaderTextStyle}" TextWrapping="Wrap"/>
<!-- Content -->
<Grid Grid.Row="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Text="Input" Style="{StaticResource H2Style}"/>
<TextBlock x:Name="ScenarioListLabel" Text="Select Scenario:" Grid.Row="1" Style="{StaticResource SubheaderTextStyle}" Margin="0,5,0,0" />
<ListBox x:Name="Scenarios" Margin="0,0,20,0" Grid.Row="2" AutomationProperties.Name="Scenarios" HorizontalAlignment="Left"
VerticalAlignment="Top" ScrollViewer.HorizontalScrollBarVisibility="Auto"
AutomationProperties.LabeledBy="{Binding ElementName=ScenarioListLabel}" MaxHeight="125" Padding="0,0,27,0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock x:Name="DescriptionText" Margin="0,5,0,0" Text="Description:" Style="{StaticResource SubheaderTextStyle}" Grid.Row="1" Grid.Column="1"/>
<!-- Input Scenarios -->
<UserControl x:Name="InputSection" Margin="0,5,0,0" IsTabStop="False" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<!-- Output section -->
<TextBlock Text="Output" Grid.Row="5" Margin="0,25,0,20" Style="{StaticResource H2Style}" Grid.ColumnSpan="2"/>
<TextBlock x:Name="StatusBlock" Grid.Row="6" Margin="0,0,0,5" Grid.ColumnSpan="2" Visibility="Collapsed"/>
<!-- Output Scenarios -->
<UserControl x:Name="OutputSection" Grid.Row="7" Grid.ColumnSpan="2" BorderThickness="0"/>
</Grid>
</Grid>
</Grid>
</ScrollViewer>
<!-- Footer -->
<Grid x:Name="Footer" Grid.Row="3" Margin="0,10,0,10" VerticalAlignment="Bottom" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Source="Assets/microsoft-sdk.png" AutomationProperties.Name="Microsoft Logo" Stretch="None" HorizontalAlignment="Left"/>
<TextBlock Style="{StaticResource FooterStyle}" Text="? Microsoft Corporation. All rights reserved." TextWrapping="Wrap" Grid.Row="1" HorizontalAlignment="Left"/>
<StackPanel x:Name="FooterPanel" Orientation="Horizontal" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right">
<HyperlinkButton Content="Terms of use" Tag="http://www.microsoft.com/About/Legal/EN/US/IntellectualProperty/Copyright/default.aspx"
Click="Footer_Click" FontSize="12" Style="{StaticResource HyperlinkStyle}"/>
<TextBlock Text="|" Style="{StaticResource SeparatorStyle}" VerticalAlignment="Center"/>
<HyperlinkButton Content="Trademarks" Tag="http://www.microsoft.com/About/Legal/EN/US/IntellectualProperty/Trademarks/EN-US.aspx"
Click="Footer_Click" FontSize="12" Style="{StaticResource HyperlinkStyle}"/>
<TextBlock Text="|" Style="{StaticResource SeparatorStyle}" VerticalAlignment="Center"/>
<HyperlinkButton Content="Privacy Statement" Tag="http://privacy.microsoft.com" Click="Footer_Click" FontSize="12" Style="{StaticResource HyperlinkStyle}"/>
</StackPanel>
</Grid>
</Grid>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state -->
<VisualStateGroup>
<VisualState x:Name="FullScreenLandscape">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="Filled">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="ContentRoot">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Thickness>20,20,20,20</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.HorizontalAlignment)" Storyboard.TargetName="FooterPanel">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<HorizontalAlignment>Left</HorizontalAlignment>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</common:LayoutAwarePage>