在UWP开发中,微软提供了新的用户许可验证方式-指纹(生物识别)、Pin、密码验证。在爆料的新型Win10 Mobile移动设备中,会增加虹膜识别等先进的用户身份识别技术,微软现在统一了身份验证的API,将生物识别认证和传统的密码识别封装为系统API供开发者调用,调用者只需关心认证的结果,而无需担心用户使用的是虹膜识别还是指纹还是密码等其他的识别技术。

通过UserConsentVerifier类可以提高应用程序的安全性,例如,你可以授权应用程序的购买,或者访问受限制的资源之前需要指纹验证。下面看下的UserConsentVerifier类结构。

Windows.Security.Credentials.UI. UserConsentVerifier 类中,微软提供了两个静态方法:

public static IAsyncOperation<UserConsentVerifierAvailability> CheckAvailabilityAsync();

public static IAsyncOperation<UserConsentVerificationResult> RequestVerificationAsync(System.String message);

CheckAvailabilityAsync()方法是用来检测用户的身份识别器是否可用

RequestVerificationAsync() 方法是请求用户身份识别,参数为身份验证对话框的提示语

下面我们使用个例子展示下这个新的识别技术的使用。

首先我们创建一个页面,使用SplitView做一个带有汉堡包菜单的页面MainPage.xaml

 <Page.Resources>
<local:ScenarioBindingConverter x:Key="ScenarioConverter"></local:ScenarioBindingConverter>
</Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="wideState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="641" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Splitter.DisplayMode" Value="Inline"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="narrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Splitter.DisplayMode" Value="Overlay"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<SplitView x:Name="Splitter" IsPaneOpen="True" Grid.Column="1">
<SplitView.Pane>
<RelativePanel Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
<StackPanel x:Name="HeaderPanel" Orientation="Horizontal">
<TextBlock x:Name="Header" Text="Windows 10 sample" Style="{StaticResource TagLineTextStyle}" Margin="0,15,0,0" />
</StackPanel>
<TextBlock x:Name="SampleTitle" Text="Sample Title Here" Style="{StaticResource SampleHeaderTextStyle}" TextWrapping="Wrap" RelativePanel.Below="HeaderPanel" Margin="0,10,0,0"/>
<ListBox x:Name="ScenarioControl" SelectionChanged="ScenarioControl_SelectionChanged"
SelectionMode="Single" HorizontalAlignment="Left" Style="{StaticResource ScenarioListBoxStyle}"
VerticalAlignment="Top" RelativePanel.Below="SampleTitle" Margin="0,10,0,0" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource ScenarioConverter}}" Style="{StaticResource ListItemTextStyle}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</RelativePanel>
</SplitView.Pane>
<RelativePanel>
<Frame x:Name="ScenarioFrame" Margin="0,5,0,0" RelativePanel.AlignTopWithPanel="True" RelativePanel.Above="StatusPanel"/>
<StackPanel x:Name="StatusPanel" Orientation="Vertical" RelativePanel.AlignBottomWithPanel="True">
<TextBlock x:Name="StatusLabel" Margin="0,0,0,10" TextWrapping="Wrap" Text="Status:" />
<Border x:Name="StatusBorder" Margin="0,0,0,0" Visibility="Collapsed" >
<TextBlock x:Name="StatusBlock" FontWeight="Bold" MaxHeight="200" MinWidth="{Binding ElementName=Splitter, Path=ActualWidth}" TextTrimming="CharacterEllipsis" Margin="20,10,10,20" TextWrapping="Wrap"/>
</Border>
</StackPanel>
</RelativePanel>
</SplitView>
<Border Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
<ToggleButton Style="{StaticResource SymbolButton}" Click="Button_Click" VerticalAlignment="Top" Foreground="{ThemeResource ApplicationForegroundThemeBrush}">
<ToggleButton.Content>
<FontIcon x:Name="Hamburger" FontFamily="Segoe MDL2 Assets" Glyph="" Margin="0,10,0,0"/>
</ToggleButton.Content>
</ToggleButton>
</Border>
</Grid>

上面用到的样式文件如下:

 <Style x:Key="SymbolButton" TargetType="ToggleButton">
<Setter Property="Background" Value="{ThemeResource ToggleButtonBackgroundThemeBrush}"/>
<Setter Property="Foreground" Value="{ThemeResource ToggleButtonForegroundThemeBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource ToggleButtonBorderThemeBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource ToggleButtonBorderThemeThickness}"/>
<Setter Property="Padding" Value="12,4,12,5"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonCheckedPressedBackgroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonDisabledForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonCheckedBackgroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="CheckedPointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonCheckedPointerOverBackgroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="CheckedPressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonCheckedPressedBackgroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="CheckedDisabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonCheckedDisabledForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Indeterminate"/>
<VisualState x:Name="IndeterminatePointerOver">
</VisualState>
<VisualState x:Name="IndeterminatePressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonPressedForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="IndeterminateDisabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonDisabledForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualWhite"/>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualBlack"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="PointerFocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="1.5" StrokeEndLineCap="Square" Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1"/>
<Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="0.5" StrokeEndLineCap="Square" Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="BasicTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}">
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Margin" Value="0,0,0,10"/>
</Style> <Style x:Key="TagLineTextStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Light"/>
<Setter Property="FontSize" Value="16"/>
</Style> <Style x:Key="SampleHeaderTextStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Light"/>
<Setter Property="FontSize" Value="26.667"/>
</Style> <Style x:Key="ListItemTextStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Semilight"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Margin" Value="10,0,0,0"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style> <Style x:Key="CopyrightTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}">
<Setter Property="FontWeight" Value="Normal"/>
</Style> <Style x:Key="ScenarioHeaderTextStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Light"/>
<Setter Property="FontSize" Value="26.667"/>
</Style> <Style x:Key="ScenarioDescriptionTextStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Light"/>
<Setter Property="FontSize" Value="16"/>
</Style> <Style x:Key="BaseMessageStyle" 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="SeparatorStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="9"/>
<Setter Property="Foreground" Value="Gray"/>
</Style> <Style x:Key="HyperlinkStyle" TargetType="HyperlinkButton">
<Setter Property="Padding" Value="1"/>
<Setter Property="Foreground" Value="Gray"/>
</Style> <!-- Default style for Windows.UI.Xaml.Controls.ListBoxItem -->
<Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="TabNavigation" Value="Local" />
<Setter Property="Padding" Value="8,10" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="LayoutRoot"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemPointerOverBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemPointerOverForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemDisabledForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PressedBackground"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemPressedForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected" />
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="InnerGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="SelectedUnfocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="InnerGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="SelectedDisabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="InnerGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedDisabledBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedDisabledForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="SelectedPointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="InnerGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedPointerOverBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="SelectedPressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="InnerGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxItemSelectedForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="FocusVisualWhite"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0" />
<DoubleAnimation Storyboard.TargetName="FocusVisualBlack"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0" />
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused" />
<VisualState x:Name="PointerFocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="InnerGrid"
Background="Transparent">
<Rectangle x:Name="PressedBackground"
Fill="{ThemeResource ListBoxItemPressedBackgroundThemeBrush}"
Opacity="0" />
<ContentPresenter x:Name="ContentPresenter"
Content="{TemplateBinding Content}"
ContentTransitions="{TemplateBinding ContentTransitions}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}" />
<Rectangle x:Name="FocusVisualWhite"
Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
StrokeEndLineCap="Square"
StrokeDashArray="1,1"
Opacity="0"
StrokeDashOffset=".5" />
<Rectangle x:Name="FocusVisualBlack"
Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
StrokeEndLineCap="Square"
StrokeDashArray="1,1"
Opacity="0"
StrokeDashOffset="1.5" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style x:Key="ScenarioListBoxStyle" TargetType="ListBox">
<Setter Property="Foreground" Value="{ThemeResource ListBoxForegroundThemeBrush}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="{ThemeResource ListBoxBorderThemeThickness}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled"/>
<Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="True"/>
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Enabled"/>
<Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="True"/>
<Setter Property="ScrollViewer.ZoomMode" Value="Disabled"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
<Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="TabNavigation" Value="Once"/>
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel Background="Transparent"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border x:Name="LayoutRoot" BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ScrollViewer x:Name="ScrollViewer" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

然后在App.xaml.cs中引用我们创建好的样式文件,这样MainPage.xaml就可以使用该外部样式文件里面的样式了。

 <Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

接着创建菜单项的Model,创建一个类Scenario:

 public class Scenario
{
public string Title { get; set; }
public Type ClassType { get; set; }
}

然后在MainPage.xaml.cs中实现跳转的逻辑:

 public sealed partial class MainPage : Page
{
public static MainPage Current;
public const string FEATURE_NAME = "User Consent Verifier"; List<Scenario> scenarios = new List<Scenario>
{
new Scenario() { Title="Check Consent Availability", ClassType=typeof(Scenario1_CheckConsentAvailability)},
new Scenario() { Title="Request Consent", ClassType=typeof(Scenario2_RequestConsent)}
}; public MainPage()
{
this.InitializeComponent();
Current = this;
SampleTitle.Text = FEATURE_NAME;
} protected override void OnNavigatedTo(NavigationEventArgs e)
{
ScenarioControl.ItemsSource = scenarios;
if (Window.Current.Bounds.Width < )
{
ScenarioControl.SelectedIndex = -;
}
else
{
ScenarioControl.SelectedIndex = ;
}
} private void ScenarioControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
NotifyUser(String.Empty, NotifyType.StatusMessage); ListBox scenarioListBox = sender as ListBox;
Scenario s = scenarioListBox.SelectedItem as Scenario;
if (s != null)
{
ScenarioFrame.Navigate(s.ClassType);
if (Window.Current.Bounds.Width < )
{
Splitter.IsPaneOpen = false;
StatusBorder.Visibility = Visibility.Collapsed;
}
}
} public List<Scenario> Scenarios
{
get { return this.scenarios; }
} public void NotifyUser(string strMessage, NotifyType type)
{
switch (type)
{
case NotifyType.StatusMessage:
StatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Green);
break;
case NotifyType.ErrorMessage:
StatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Red);
break;
}
StatusBlock.Text = strMessage;
StatusBorder.Visibility = (StatusBlock.Text != String.Empty) ? Visibility.Visible : Visibility.Collapsed;
} private void Button_Click(object sender, RoutedEventArgs e)
{
Splitter.IsPaneOpen = (Splitter.IsPaneOpen == true) ? false : true;
StatusBorder.Visibility = Visibility.Collapsed;
}
}
public enum NotifyType
{
StatusMessage,
ErrorMessage
}; public class ScenarioBindingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
Scenario s = value as Scenario;
return (MainPage.Current.Scenarios.IndexOf(s) + ) + ") " + s.Title;
} public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return true;
}
}

至此,首页已经完工,一个带有汉堡包菜单的主页,然后我们创建检测用户身份验证器是否可用的页面Scenario1_CheckConsentAvailability.xaml,前台代码如下:

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="RootGrid" Margin="12,20,12,12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Margin="0,0,0,10">
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
检测用户的身份验证器是否可以使用
</TextBlock>
</StackPanel> <ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0" Grid.Row="1">
<Button x:Name="CheckAvailability" Content="Check Availability" Margin="0,0,10,0" Click="CheckAvailability_Click"/>
</StackPanel>
</StackPanel>
</ScrollViewer> <Border x:Name="ErrorBorder" Background="Red" Grid.Row="2"/>
<TextBlock x:Name="StatusBlock" Grid.Row="2" Margin="12, 10, 12, 10" Visibility="Collapsed"/>
</Grid>
</Grid>

后台实现检测用户身份验证器是否可用的代码:

     private async void CheckAvailability_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
b.IsEnabled = false;
try
{
UserConsentVerifierAvailability consentAvailability = await Windows.Security.Credentials.UI.UserConsentVerifier.CheckAvailabilityAsync();
switch (consentAvailability)
{
case UserConsentVerifierAvailability.Available:
{
rootPage.NotifyUser("用户身份验证器可用", NotifyType.StatusMessage);
break;
} case UserConsentVerifierAvailability.DeviceBusy:
{
rootPage.NotifyUser("验证器正忙或不可用", NotifyType.ErrorMessage);
break;
} case UserConsentVerifierAvailability.DeviceNotPresent:
{
rootPage.NotifyUser("没有发现验证设备", NotifyType.ErrorMessage);
break;
} case UserConsentVerifierAvailability.DisabledByPolicy:
{
rootPage.NotifyUser("策略组禁用了生物验证", NotifyType.ErrorMessage);
break;
} case UserConsentVerifierAvailability.NotConfiguredForUser:
{
rootPage.NotifyUser("该用户没有配置验证信息", NotifyType.ErrorMessage);
break;
} default:
{
rootPage.NotifyUser("验证器不可用", NotifyType.ErrorMessage);
break;
}
}
}
catch (Exception ex)
{
rootPage.NotifyUser("验证器出错了, Exception: " + ex.ToString(), NotifyType.ErrorMessage);
}
finally
{
b.IsEnabled = true;
}
}

验证页面完毕,创建请求身份验证的页面Scenario2_RequestConsent.xaml,前台代码如下:

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="RootGrid" Margin="12,20,12,12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Margin="0,0,0,10">
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
请求身份验证并发送一个消息给用户
</TextBlock>
</StackPanel> <ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Text="Message:" VerticalAlignment="Center" Width="85"/>
<TextBox x:Name="Message" Text="Message to user" Width="300"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button x:Name="RequestConsent" Content="Request Consent" Margin="85,0,0,0" Click="RequestConsent_Click"/>
</StackPanel>
</StackPanel>
</ScrollViewer> <Border x:Name="ErrorBorder" Background="Red" Grid.Row="2"/>
<TextBlock x:Name="StatusBlock" Grid.Row="2" Margin="12, 10, 12, 10" Visibility="Collapsed"/>
</Grid>
</Grid>

后台请求验证的代码:

 private async void RequestConsent_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
b.IsEnabled = false; if (!String.IsNullOrEmpty(Message.Text))
{
try
{
UserConsentVerificationResult consentResult = await Windows.Security.Credentials.UI.UserConsentVerifier.RequestVerificationAsync(Message.Text);
switch (consentResult)
{
case UserConsentVerificationResult.Verified:
{
rootPage.NotifyUser("用户已通过验证", NotifyType.StatusMessage);
break;
} case UserConsentVerificationResult.DeviceBusy:
{
rootPage.NotifyUser("验证器正在忙或者不可用", NotifyType.ErrorMessage);
break;
} case UserConsentVerificationResult.DeviceNotPresent:
{
rootPage.NotifyUser("没有发现验证设备", NotifyType.ErrorMessage);
break;
} case UserConsentVerificationResult.DisabledByPolicy:
{
rootPage.NotifyUser("策略组禁用了生物验证", NotifyType.ErrorMessage);
break;
} case UserConsentVerificationResult.NotConfiguredForUser:
{
rootPage.NotifyUser("该用户没有配置验证信息", NotifyType.ErrorMessage);
break;
} case UserConsentVerificationResult.RetriesExhausted:
{
rootPage.NotifyUser("经过10次失败的验证后,没有经过验证", NotifyType.ErrorMessage);
break;
}
case UserConsentVerificationResult.Canceled:
{
rootPage.NotifyUser("取消验证", NotifyType.ErrorMessage);
break;
} default:
{
rootPage.NotifyUser("不可用", NotifyType.ErrorMessage);
break;
}
}
}
catch (Exception ex)
{
rootPage.NotifyUser("调用身份验证器出错, Exception: " + ex.ToString(), NotifyType.ErrorMessage);
}
finally
{
b.IsEnabled = true;
}
}
else
{
rootPage.NotifyUser("文本框值为空", NotifyType.ErrorMessage);
b.IsEnabled = true;
}
}

Ok,来看下效果:

UWP/Win10新特性系列—UserConsentVerifier-LMLPHP

推荐一个UWP开发群:53078485 大家可以进来一起学习~~

04-26 14:59