This commit is contained in:
Nikola Metulev 2018-05-21 12:55:25 -07:00
Родитель 57750a8487
Коммит 26c3bf89b0
33 изменённых файлов: 4 добавлений и 3471 удалений

Просмотреть файл

@ -1,33 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Defines the events for the <see cref="AadLogin"/> control.
/// </summary>
public partial class AadLogin : Button
{
/// <summary>
/// Occurs when the user is logged in.
/// </summary>
public event EventHandler<SignInEventArgs> SignInCompleted;
/// <summary>
/// Occurs when the user is logged out.
/// </summary>
public event EventHandler SignOutCompleted;
}
}

Просмотреть файл

@ -1,162 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Defines the properties for the <see cref="AadLogin"/> control.
/// </summary>
public partial class AadLogin : Button
{
/// <summary>
/// Gets required delegated permissions for the <see cref="AadLogin"/> control
/// </summary>
public static string[] RequiredDelegatedPermissions
{
get
{
return new string[] { "User.Read" };
}
}
/// <summary>
/// Identifies the <see cref="DefaultImage"/> dependency property.
/// </summary>
public static readonly DependencyProperty DefaultImageProperty = DependencyProperty.Register(
nameof(DefaultImage),
typeof(BitmapImage),
typeof(AadLogin),
new PropertyMetadata(null));
/// <summary>
/// Identifies the <see cref="View"/> dependency property.
/// </summary>
public static readonly DependencyProperty ViewProperty = DependencyProperty.Register(
nameof(View),
typeof(ViewType),
typeof(AadLogin),
new PropertyMetadata(ViewType.PictureOnly));
/// <summary>
/// Identifies the <see cref="AllowSignInAsDifferentUser"/> dependency property.
/// </summary>
public static readonly DependencyProperty AllowSignInAsDifferentUserProperty = DependencyProperty.Register(
nameof(AllowSignInAsDifferentUser),
typeof(bool),
typeof(AadLogin),
new PropertyMetadata(true));
/// <summary>
/// Identifies the <see cref="SignInDefaultText"/> dependency property.
/// </summary>
public static readonly DependencyProperty SignInDefaultTextProperty = DependencyProperty.Register(
nameof(SignInDefaultText),
typeof(string),
typeof(AadLogin),
new PropertyMetadata("Sign In"));
/// <summary>
/// Identifies the <see cref="SignOutDefaultText"/> dependency property.
/// </summary>
public static readonly DependencyProperty SignOutDefaultTextProperty = DependencyProperty.Register(
nameof(SignOutDefaultText),
typeof(string),
typeof(AadLogin),
new PropertyMetadata("Sign Out"));
/// <summary>
/// Identifies the <see cref="SignInAnotherUserDefaultText"/> dependency property.
/// </summary>
public static readonly DependencyProperty SignInAnotherUserDefaultTextProperty = DependencyProperty.Register(
nameof(SignInAnotherUserDefaultText),
typeof(string),
typeof(AadLogin),
new PropertyMetadata("Sign in with another account"));
/// <summary>
/// Identifies the <see cref="CurrentUserId"/> dependency property.
/// </summary>
public static readonly DependencyProperty CurrentUserIdProperty = DependencyProperty.Register(
nameof(CurrentUserId),
typeof(string),
typeof(AadLogin),
new PropertyMetadata(null));
/// <summary>
/// Gets or sets the default user photo
/// </summary>
public BitmapImage DefaultImage
{
get { return (BitmapImage)GetValue(DefaultImageProperty); }
set { SetValue(DefaultImageProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating which view type will be presented, the default value is PictureOnly.
/// </summary>
public ViewType View
{
get { return (ViewType)GetValue(ViewProperty); }
set { SetValue(ViewProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating whether AllowSignInAsDifferentUser menu button is enabled for logged in user.
/// </summary>
public bool AllowSignInAsDifferentUser
{
get { return (bool)GetValue(AllowSignInAsDifferentUserProperty); }
set { SetValue(AllowSignInAsDifferentUserProperty, value); }
}
/// <summary>
/// Gets or sets a value for default sign-in text.
/// </summary>
public string SignInDefaultText
{
get { return (string)GetValue(SignInDefaultTextProperty); }
set { SetValue(SignInDefaultTextProperty, value); }
}
/// <summary>
/// Gets or sets a value for default sign-out text.
/// </summary>
public string SignOutDefaultText
{
get { return (string)GetValue(SignOutDefaultTextProperty); }
set { SetValue(SignOutDefaultTextProperty, value); }
}
/// <summary>
/// Gets or sets a value for default text of the Sign-in-with-another-account button.
/// </summary>
public string SignInAnotherUserDefaultText
{
get { return (string)GetValue(SignInAnotherUserDefaultTextProperty); }
set { SetValue(SignInAnotherUserDefaultTextProperty, value); }
}
/// <summary>
/// Gets the unique identifier for current signed in user.
/// </summary>
public string CurrentUserId
{
get { return (string)GetValue(CurrentUserIdProperty); }
private set { SetValue(CurrentUserIdProperty, value); }
}
}
}

Просмотреть файл

@ -1,144 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The AAD Login Control leverages MSAL libraries to support basic AAD sign-in processes for Microsoft Graph and beyond.
/// </summary>
[TemplatePart(Name = "RootGrid", Type = typeof(Grid))]
[TemplatePart(Name = "ContentPresenter", Type = typeof(ContentPresenter))]
public partial class AadLogin : Button
{
private AadAuthenticationManager _aadAuthenticationManager = AadAuthenticationManager.Instance;
/// <summary>
/// Initializes a new instance of the <see cref="AadLogin"/> class.
/// </summary>
public AadLogin()
{
DefaultStyleKey = typeof(AadLogin);
}
/// <summary>
/// Override default OnApplyTemplate to capture child controls
/// </summary>
protected override void OnApplyTemplate()
{
ApplyTemplate();
AutomationProperties.SetName(this, SignInDefaultText);
Click += async (object sender, RoutedEventArgs e) =>
{
if (!_aadAuthenticationManager.IsAuthenticated)
{
Flyout = null;
await SignInAsync();
}
else
{
Flyout = GenerateMenuItems();
}
};
_aadAuthenticationManager.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
{
if (e.PropertyName == nameof(_aadAuthenticationManager.CurrentUserId))
{
CurrentUserId = _aadAuthenticationManager.CurrentUserId;
}
};
if (_aadAuthenticationManager.IsAuthenticated)
{
CurrentUserId = _aadAuthenticationManager.CurrentUserId;
}
}
/// <summary>
/// This method is used to prompt to login screen.
/// </summary>
/// <returns>True if sign in successfully, otherwise false</returns>
public async Task<bool> SignInAsync()
{
if (await _aadAuthenticationManager.ConnectAsync())
{
AutomationProperties.SetName(this, string.Empty);
Flyout = GenerateMenuItems();
SignInCompleted?.Invoke(this, new SignInEventArgs()
{
GraphClient = await _aadAuthenticationManager.GetGraphServiceClientAsync()
});
return true;
}
return false;
}
/// <summary>
/// This method is used to sign out the currently signed on user
/// </summary>
public void SignOut()
{
_aadAuthenticationManager.SignOut();
SignOutCompleted?.Invoke(this, EventArgs.Empty);
}
private MenuFlyout GenerateMenuItems()
{
MenuFlyout menuFlyout = new MenuFlyout();
if (AllowSignInAsDifferentUser)
{
MenuFlyoutItem signinanotherItem = new MenuFlyoutItem
{
Text = SignInAnotherUserDefaultText
};
AutomationProperties.SetName(signinanotherItem, SignInAnotherUserDefaultText);
signinanotherItem.Click += async (object sender, RoutedEventArgs e) =>
{
if (await _aadAuthenticationManager.ConnectForAnotherUserAsync())
{
var graphClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
SignInCompleted?.Invoke(this, new SignInEventArgs()
{
GraphClient = graphClient
});
}
};
menuFlyout.Items.Add(signinanotherItem);
}
MenuFlyoutItem signoutItem = new MenuFlyoutItem
{
Text = SignOutDefaultText
};
AutomationProperties.SetName(signoutItem, SignOutDefaultText);
signoutItem.Click += (object sender, RoutedEventArgs e) => _aadAuthenticationManager.SignOut();
menuFlyout.Items.Add(signoutItem);
return menuFlyout;
}
}
}

Просмотреть файл

@ -1,87 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph">
<Style TargetType="controls:AadLogin">
<Setter Property="Background" Value="{ThemeResource ButtonBackground}"/>
<Setter Property="Foreground" Value="{ThemeResource ButtonForeground}"/>
<Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}"/>
<Setter Property="Padding" Value="8,4,8,4"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="UseSystemFocusVisuals" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:AadLogin">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPointerOver}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}"/>
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}"/>
</ObjectAnimationUsingKeyFrames>
<PointerDownThemeAnimation Storyboard.TargetName="RootGrid"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
<ContentPresenter.Content>
<controls:ProfileCard
DisplayMode="{TemplateBinding View}"
DefaultImage="{TemplateBinding DefaultImage}"
UserId="{TemplateBinding CurrentUserId}"
LargeProfileTitleDefaultText="{TemplateBinding SignInDefaultText}"
NormalMailDefaultText="{TemplateBinding SignInDefaultText}"/>
</ContentPresenter.Content>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -1,34 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using Microsoft.Graph;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Arguments relating to a sign-in event of Aadlogin control
/// </summary>
public class SignInEventArgs
{
internal SignInEventArgs()
{
}
/// <summary>
/// Gets the graph service client with authorized token.
/// </summary>
public GraphServiceClient GraphClient
{
get; internal set;
}
}
}

Просмотреть файл

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
<g id="TEMPLATE" display="none">
<g display="inline">
<path fill="#D0D0D0" d="M32,0v32H0V0H32 M33-1h-1H0h-1v1v32v1h1h32h1v-1V0V-1L33-1z"/>
</g>
<path display="inline" opacity="0.1" fill="#FF1D25" d="M0,0v32h32V0H0z M30,30H2V2h28V30z"/>
</g>
<g id="ICONS">
<polygon fill="#A6A6A6" points="2,26 2,9 16,9 19,6 30,6 30,26 "/>
<polygon fill="#828282" points="19,6 16,9 19,12 30,12 30,6 "/>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="6.7687" y1="4.9986" x2="26.7085" y2="28.7619">
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
<stop offset="0.8625" style="stop-color:#000000;stop-opacity:0.1725"/>
<stop offset="1" style="stop-color:#000000;stop-opacity:0.2"/>
</linearGradient>
<polygon fill="url(#SVGID_1_)" points="2,26 2,9 16,9 19,6 30,6 30,26 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="23.4439" y1="5.4264" x2="22.8394" y2="12.3359">
<stop offset="0" style="stop-color:#828282;stop-opacity:0"/>
<stop offset="0.4267" style="stop-color:#808080;stop-opacity:0.1067"/>
<stop offset="0.5804" style="stop-color:#797979;stop-opacity:0.1451"/>
<stop offset="0.6899" style="stop-color:#6E6E6E;stop-opacity:0.1725"/>
<stop offset="0.7785" style="stop-color:#5D5D5D;stop-opacity:0.1946"/>
<stop offset="0.8543" style="stop-color:#474747;stop-opacity:0.2136"/>
<stop offset="0.9215" style="stop-color:#2B2B2B;stop-opacity:0.2304"/>
<stop offset="0.9808" style="stop-color:#0C0C0C;stop-opacity:0.2452"/>
<stop offset="1" style="stop-color:#000000;stop-opacity:0.25"/>
</linearGradient>
<polygon fill="url(#SVGID_2_)" points="19,6 16,9 19,12 30,12 30,6 "/>
<polygon opacity="0.15" fill="#FFFFFF" points="30,12 30,12.5 18.7708,12.5 15.25,9 16,9 19.0208,12 "/>
</g>
</svg>

До

Ширина:  |  Высота:  |  Размер: 2.1 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 389 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.1 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 610 B

Просмотреть файл

@ -1,281 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.Graph;
using Microsoft.Identity.Client;
using Microsoft.Toolkit.Services.MicrosoftGraph;
using static Microsoft.Toolkit.Services.MicrosoftGraph.MicrosoftGraphEnums;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Microsoft Graph authentication manager for Microsoft Toolkit Graph controls using Microsoft Authentication Library (MSAL)
/// </summary>
public sealed class AadAuthenticationManager : MicrosoftGraphService, INotifyPropertyChanged
{
private static PublicClientApplication _publicClientApp = null;
private static AadAuthenticationManager _instance;
/// <summary>
/// Gets public singleton property.
/// </summary>
public static new AadAuthenticationManager Instance => _instance ?? (_instance = new AadAuthenticationManager());
private AadAuthenticationManager()
{
}
/// <summary>
/// Gets current application ID.
/// </summary>
public string ClientId
{
get
{
return AppClientId;
}
}
/// <summary>
/// Gets current permission scopes.
/// </summary>
public string[] Scopes
{
get
{
return DelegatedPermissionScopes;
}
}
/// <summary>
/// Gets a value indicating whether authenticated.
/// </summary>
public bool IsAuthenticated
{
get
{
return _isAuthenticated;
}
private set
{
if (value != _isAuthenticated)
{
_isAuthenticated = value;
NotifyPropertyChanged(nameof(IsAuthenticated));
}
}
}
private bool _isAuthenticated = false;
/// <summary>
/// Gets current user id.
/// </summary>
public string CurrentUserId
{
get
{
return _currentUserId;
}
private set
{
if (value != _currentUserId)
{
_currentUserId = value;
NotifyPropertyChanged(nameof(CurrentUserId));
}
}
}
private string _currentUserId;
/// <summary>
/// Gets field to store the model of authentication
/// V1 Only for Work or Scholar account
/// V2 for MSA and Work or Scholar account
/// </summary>
public new AuthenticationModel AuthenticationModel
{
get
{
return base.AuthenticationModel;
}
}
/// <summary>
/// Gets store a reference to an instance of the underlying data provider.
/// </summary>
public new GraphServiceClient GraphProvider
{
get
{
return base.GraphProvider;
}
}
/// <summary>
/// Gets fields to store a MicrosoftGraphServiceMessages instance
/// </summary>
public new MicrosoftGraphUserService User
{
get
{
return base.User;
}
}
/// <summary>
/// Property changed eventHandler for notification.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Initialize for the <see cref="AadAuthenticationManager"/> class
/// </summary>
/// <param name="clientId">Application client ID for MSAL v2 endpoints</param>
/// <param name="scopes">Permission scopes for MSAL v2 endpoints</param>
public void Initialize(string clientId, params string[] scopes)
{
if (string.IsNullOrEmpty(clientId))
{
throw new ArgumentNullException(nameof(clientId));
}
if (scopes.Length == 0)
{
throw new ArgumentNullException(nameof(scopes));
}
base.AuthenticationModel = AuthenticationModel.V2;
base.Initialize(clientId, ServicesToInitialize.UserProfile, scopes);
}
/// <summary>
/// Initialize Microsoft Graph.
/// </summary>
/// <typeparam name="T">Concrete type that inherits IMicrosoftGraphUserServicePhotos.</typeparam>
/// <param name='appClientId'>Azure AD's App client id</param>
/// <param name="servicesToInitialize">A combination of value to instanciate different services</param>
/// <param name="delegatedPermissionScopes">Permission scopes for MSAL v2 endpoints</param>
/// <param name="uiParent">UiParent instance - required for Android</param>
/// <param name="redirectUri">Redirect Uri - required for Android</param>
/// <returns>Success or failure.</returns>
[Obsolete("This is not supported in this class.", true)]
public new bool Initialize<T>(string appClientId, ServicesToInitialize servicesToInitialize = ServicesToInitialize.Message | ServicesToInitialize.UserProfile | ServicesToInitialize.Event, string[] delegatedPermissionScopes = null, UIParent uiParent = null, string redirectUri = null)
where T : IMicrosoftGraphUserServicePhotos, new()
{
throw new NotImplementedException();
}
/// <summary>
/// Initialize Microsoft Graph.
/// </summary>
/// <param name='appClientId'>Azure AD's App client id</param>
/// <param name="servicesToInitialize">A combination of value to instanciate different services</param>
/// <param name="delegatedPermissionScopes">Permission scopes for MSAL v2 endpoints</param>
/// <param name="uiParent">UiParent instance - required for Android</param>
/// <param name="redirectUri">Redirect Uri - required for Android</param>
/// <returns>Success or failure.</returns>
[Obsolete("This is not supported in this class.", true)]
public new bool Initialize(string appClientId, ServicesToInitialize servicesToInitialize = ServicesToInitialize.Message | ServicesToInitialize.UserProfile | ServicesToInitialize.Event, string[] delegatedPermissionScopes = null, UIParent uiParent = null, string redirectUri = null)
{
throw new NotImplementedException();
}
internal async Task<bool> ConnectAsync()
{
try
{
IsAuthenticated = await LoginAsync();
if (IsAuthenticated)
{
CurrentUserId = (await User.GetProfileAsync(new MicrosoftGraphUserFields[1] { MicrosoftGraphUserFields.Id })).Id;
}
}
catch (MsalServiceException ex)
{
// Swallow error in case of authentication cancellation.
if (ex.ErrorCode != "authentication_canceled"
&& ex.ErrorCode != "access_denied")
{
throw ex;
}
}
return IsAuthenticated;
}
internal Task<GraphServiceClient> GetGraphServiceClientAsync()
{
return Task.FromResult(GraphProvider);
}
internal async void SignOut()
{
await Logout();
CurrentUserId = string.Empty;
IsAuthenticated = false;
}
internal async Task<bool> ConnectForAnotherUserAsync()
{
if (!IsInitialized)
{
throw new InvalidOperationException("Microsoft Graph not initialized.");
}
try
{
_publicClientApp = new PublicClientApplication(ClientId);
AuthenticationResult result = await _publicClientApp.AcquireTokenAsync(Scopes);
var signedUser = result.User;
foreach (var user in _publicClientApp.Users)
{
if (user.Identifier != signedUser.Identifier)
{
_publicClientApp.Remove(user);
}
}
await LoginAsync();
CurrentUserId = (await User.GetProfileAsync(new MicrosoftGraphUserFields[1] { MicrosoftGraphUserFields.Id })).Id;
return true;
}
catch (MsalServiceException ex)
{
// Swallow error in case of authentication cancellation.
if (ex.ErrorCode != "authentication_canceled"
&& ex.ErrorCode != "access_denied")
{
throw ex;
}
}
return false;
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Просмотреть файл

@ -1,151 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Graph;
using Microsoft.Toolkit.Uwp.UI.Extensions;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Defines the events for the <see cref="PeoplePicker"/> control.
/// </summary>
public partial class PeoplePicker : Control
{
private static void AllowMultiplePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as PeoplePicker;
if (!control.AllowMultiple)
{
control.Selections.Clear();
control.RaiseSelectionChanged();
control._searchBox.Text = string.Empty;
}
}
private void ClearAndHideSearchResultListBox()
{
SearchResultList.Clear();
_searchResultListBox.Visibility = Visibility.Collapsed;
}
private async void SearchBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
var textboxSender = (TextBox)sender;
string searchText = textboxSender.Text.Trim();
if (string.IsNullOrWhiteSpace(searchText))
{
ClearAndHideSearchResultListBox();
return;
}
_loading.IsActive = true;
searchText = Regex.Replace(searchText, "[^0-9a-zA-Z .@]", string.Empty);
int cursorPosition = textboxSender.SelectionStart;
textboxSender.Text = searchText;
textboxSender.SelectionStart = cursorPosition;
try
{
Task<GraphServiceClient> graphClient = AadAuthenticationManager.Instance.GetGraphServiceClientAsync();
var options = new List<QueryOption>
{
new QueryOption("$search", searchText)
};
IUserPeopleCollectionPage peopleList = await (await graphClient).Me.People.Request(options).GetAsync();
if (peopleList.Any())
{
List<Person> searchResult = peopleList.Where(
u => !string.IsNullOrWhiteSpace(u.UserPrincipalName)).ToList();
// Remove all selected items
foreach (Person selectedItem in Selections)
{
searchResult.RemoveAll(u => u.UserPrincipalName == selectedItem.UserPrincipalName);
}
SearchResultList.Clear();
var result = SearchResultLimit > 0
? searchResult.Take(SearchResultLimit).ToList()
: searchResult;
foreach (var item in result)
{
SearchResultList.Add(item);
}
_searchResultListBox.Visibility = Visibility.Visible;
}
else
{
ClearAndHideSearchResultListBox();
}
}
catch (Exception)
{
}
finally
{
_loading.IsActive = false;
}
}
private void SearchResultListBox_OnSelectionChanged(object sender, Windows.UI.Xaml.Controls.SelectionChangedEventArgs e)
{
if (!((sender as ListBox)?.SelectedItem is Person person))
{
return;
}
if (!AllowMultiple && Selections.Any())
{
Selections.Clear();
Selections.Add(person);
}
else
{
Selections.Add(person);
}
RaiseSelectionChanged();
_searchBox.Text = string.Empty;
}
private void SelectionsListBox_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
var elem = e.OriginalSource as FrameworkElement;
var removeButton = elem.FindAscendantByName("PersonRemoveButton");
if (removeButton != null)
{
if (removeButton.Tag is Person item)
{
Selections.Remove(item);
RaiseSelectionChanged();
}
}
}
private void RaiseSelectionChanged()
{
this.SelectionChanged?.Invoke(this, new PeopleSelectionChangedEventArgs(this.Selections));
}
}
}

Просмотреть файл

@ -1,136 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Microsoft.Graph;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Defines the properties for the <see cref="PeoplePicker"/> control.
/// </summary>
public partial class PeoplePicker : Control
{
/// <summary>
/// File is selected
/// </summary>
public event EventHandler<PeopleSelectionChangedEventArgs> SelectionChanged;
/// <summary>
/// Gets required delegated permissions for the <see cref="PeoplePicker"/> control
/// </summary>
public static string[] RequiredDelegatedPermissions
{
get
{
return new string[] { "User.Read", "User.ReadBasic.All" };
}
}
/// <summary>
/// Identifies the <see cref="AllowMultiple"/> dependency property.
/// </summary>
public static readonly DependencyProperty AllowMultipleProperty =
DependencyProperty.Register(
nameof(AllowMultiple),
typeof(bool),
typeof(PeoplePicker),
new PropertyMetadata(true, AllowMultiplePropertyChanged));
/// <summary>
/// Identifies the <see cref="SearchResultLimit"/> dependency property.
/// </summary>
public static readonly DependencyProperty SearchResultLimitProperty =
DependencyProperty.Register(
nameof(SearchResultLimit),
typeof(int),
typeof(PeoplePicker),
null);
/// <summary>
/// Identifies the <see cref="PlaceholderText"/> dependency property.
/// </summary>
public static readonly DependencyProperty PlaceholderTextProperty =
DependencyProperty.Register(
nameof(PlaceholderText),
typeof(string),
typeof(PeoplePicker),
new PropertyMetadata("Enter keywords to search people"));
/// <summary>
/// Identifies the <see cref="Selections"/> dependency property.
/// </summary>
public static readonly DependencyProperty SelectionsProperty =
DependencyProperty.Register(
nameof(Selections),
typeof(ObservableCollection<Person>),
typeof(PeoplePicker),
null);
/// <summary>
/// Identifies the <see cref="SearchResultList"/> dependency property.
/// </summary>
internal static readonly DependencyProperty SearchResultListProperty =
DependencyProperty.Register(
nameof(SearchResultList),
typeof(ObservableCollection<Person>),
typeof(PeoplePicker),
null);
/// <summary>
/// Gets or sets a value indicating whether multiple people can be selected
/// </summary>
public bool AllowMultiple
{
get => (bool)GetValue(AllowMultipleProperty);
set => SetValue(AllowMultipleProperty, value);
}
/// <summary>
/// Gets or sets the max person returned in the search results
/// </summary>
public int SearchResultLimit
{
get => (int)GetValue(SearchResultLimitProperty);
set => SetValue(SearchResultLimitProperty, value);
}
/// <summary>
/// Gets or sets the text to be displayed when no user is selected
/// </summary>
public string PlaceholderText
{
get => (string)GetValue(PlaceholderTextProperty);
set => SetValue(PlaceholderTextProperty, value);
}
/// <summary>
/// Gets or sets the selected person list.
/// </summary>
public ObservableCollection<Person> Selections
{
get => (ObservableCollection<Person>)GetValue(SelectionsProperty);
set => SetValue(SelectionsProperty, value);
}
internal ObservableCollection<Person> SearchResultList
{
get => (ObservableCollection<Person>)GetValue(SearchResultListProperty);
set => SetValue(SearchResultListProperty, value);
}
}
}

Просмотреть файл

@ -1,86 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System.Collections.ObjectModel;
using Microsoft.Graph;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The PeoplePicker Control is a simple control that allows for selection of one or more users from an organizational AD.
/// </summary>
[TemplatePart(Name = GraphAccessTokenPartName, Type = typeof(TextBox))]
[TemplatePart(Name = SearchBoxPartName, Type = typeof(TextBox))]
[TemplatePart(Name = LoadingPartName, Type = typeof(ProgressRing))]
[TemplatePart(Name = SearchResultListBoxPartName, Type = typeof(ListBox))]
[TemplatePart(Name = SelectionsListBoxPartName, Type = typeof(ListBox))]
[TemplatePart(Name = SelectionsCounterPartName, Type = typeof(TextBlock))]
public partial class PeoplePicker : Control
{
private const string GraphAccessTokenPartName = "tbGraphAccessToken";
private const string SearchBoxPartName = "SearchBox";
private const string LoadingPartName = "Loading";
private const string SearchResultListBoxPartName = "SearchResultListBox";
private const string SelectionsListBoxPartName = "SelectionsListBox";
private const string SelectionsCounterPartName = "SelectionsCounter";
private TextBox _searchBox;
private ProgressRing _loading;
private ListBox _searchResultListBox;
private ListBox _selectionsListBox;
private TextBlock _selectionsCounter;
/// <summary>
/// Initializes a new instance of the <see cref="PeoplePicker"/> class.
/// </summary>
public PeoplePicker()
{
DefaultStyleKey = typeof(PeoplePicker);
}
/// <summary>
/// Called when applying the control template.
/// </summary>
protected override void OnApplyTemplate()
{
_searchBox = GetTemplateChild("SearchBox") as TextBox;
_loading = GetTemplateChild("Loading") as ProgressRing;
_searchResultListBox = GetTemplateChild("SearchResultListBox") as ListBox;
_selectionsListBox = GetTemplateChild("SelectionsListBox") as ListBox;
_selectionsCounter = GetTemplateChild("SelectionsCounter") as TextBlock;
if (_searchBox != null
&& _loading != null
&& _searchResultListBox != null
&& _selectionsListBox != null
&& _selectionsCounter != null)
{
SearchResultList = new ObservableCollection<Person>();
Selections = Selections ?? new ObservableCollection<Person>();
if (!this.AllowMultiple)
{
_selectionsCounter.Visibility = Visibility.Collapsed;
}
_searchBox.TextChanged += SearchBox_OnTextChanged;
_searchResultListBox.SelectionChanged += SearchResultListBox_OnSelectionChanged;
_selectionsListBox.Tapped += SelectionsListBox_Tapped;
}
base.OnApplyTemplate();
}
}
}

Просмотреть файл

@ -1,95 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity">
<Style TargetType="controls:PeoplePicker">
<Setter Property="Background" Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:PeoplePicker">
<StackPanel Name="PeoplePickerContainer" DataContext="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}">
<Grid>
<TextBox Name="SearchBox"
Margin="0"
AutomationProperties.Name="Keywords"
PlaceholderText="{TemplateBinding PlaceholderText}" />
<ProgressRing Name="Loading"
Margin="0,0,30,0"
HorizontalAlignment="Right"
AutomationProperties.Name="Progress"
FlowDirection="LeftToRight"
IsActive="False" />
</Grid>
<Grid>
<StackPanel>
<ListBox Name="SelectionsListBox"
AutomationProperties.Name="Selections"
ItemsSource="{TemplateBinding Selections}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid AutomationProperties.Name="{Binding DisplayName}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:ProfileCard Grid.Row="0"
Grid.Column="0"
DisplayMode="LargeProfilePhotoLeft"
UserId="{Binding Id}" />
<TextBlock Grid.Row="0"
Grid.Column="1" />
<Button Name="PersonRemoveButton"
Tag="{Binding}"
Grid.Row="0"
Grid.Column="2"
Width="48"
Height="48"
Margin="0"
HorizontalAlignment="Right"
AutomationProperties.Name="Remove from selection"
Background="Transparent"
BorderThickness="0"
FlowDirection="LeftToRight">
<SymbolIcon Symbol="Cancel" />
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<TextBlock Name="SelectionsCounter"
Visibility="Visible"
AutomationProperties.Name="Selections Counter">
<Run><Binding Path="Selections.Count"></Binding></Run>
<Run> selected</Run>
</TextBlock>
</StackPanel>
<ListBox Name="SearchResultListBox"
Canvas.ZIndex="100"
AutomationProperties.Name="Search Results"
ItemsSource="{TemplateBinding SearchResultList}"
Visibility="Collapsed">
<ListBox.ItemTemplate>
<DataTemplate>
<controls:ProfileCard AutomationProperties.Name="{Binding DisplayName}"
DisplayMode="LargeProfilePhotoLeft"
UserId="{Binding Id}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -1,35 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using Microsoft.Graph;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
using System.Collections.ObjectModel;
/// <summary>
/// Arguments relating to the people selected event of <see cref="PeoplePicker"/> control
/// </summary>
public class PeopleSelectionChangedEventArgs
{
/// <summary>
/// Gets selected file
/// </summary>
public ObservableCollection<Person> Selections { get; private set; }
internal PeopleSelectionChangedEventArgs(ObservableCollection<Person> selections)
{
Selections = selections;
}
}
}

Просмотреть файл

@ -1,47 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Defines the events for the <see cref="ProfileCard"/> control.
/// </summary>
public partial class ProfileCard : Control
{
private static void OnUserIdPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
=> (d as ProfileCard).FetchUserInfo();
private static void OnDisplayModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var profileCard = d as ProfileCard;
ProfileCardItem profileItem = profileCard.CurrentProfileItem.Clone();
profileItem.DisplayMode = (ViewType)e.NewValue;
profileCard.CurrentProfileItem = profileItem;
}
private static void OnDefaultValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var profileCard = d as ProfileCard;
var aadManager = AadAuthenticationManager.Instance;
if (!AadAuthenticationManager.Instance.IsAuthenticated
|| string.IsNullOrEmpty(profileCard.UserId)
|| profileCard.UserId.Equals("Invalid UserId"))
{
profileCard.InitUserProfile();
}
}
}
}

Просмотреть файл

@ -1,155 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Defines the properties for the <see cref="ProfileCard"/> control.
/// </summary>
public partial class ProfileCard : Control
{
/// <summary>
/// Gets required delegated permissions for the <see cref="ProfileCard"/> control
/// </summary>
public static string[] RequiredDelegatedPermissions
{
get
{
return new string[] { "User.Read", "User.ReadBasic.All" };
}
}
/// <summary>
/// Identifies the <see cref="UserId"/> dependency property.
/// </summary>
public static readonly DependencyProperty UserIdProperty = DependencyProperty.Register(
nameof(UserId),
typeof(string),
typeof(ProfileCard),
new PropertyMetadata(string.Empty, OnUserIdPropertyChanged));
/// <summary>
/// Identifies the <see cref="DisplayMode"/> dependency property.
/// </summary>
public static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register(
nameof(DisplayMode),
typeof(ViewType),
typeof(ProfileCard),
new PropertyMetadata(ViewType.PictureOnly, OnDisplayModePropertyChanged));
/// <summary>
/// Identifies the <see cref="DefaultImage"/> dependency property.
/// </summary>
public static readonly DependencyProperty DefaultImageProperty = DependencyProperty.Register(
nameof(DefaultImage),
typeof(BitmapImage),
typeof(ProfileCard),
new PropertyMetadata(null, OnDefaultValuePropertyChanged));
/// <summary>
/// Identifies the <see cref="LargeProfileTitleDefaultText"/> dependency property.
/// </summary>
public static readonly DependencyProperty LargeProfileTitleDefaultTextProperty = DependencyProperty.Register(
nameof(LargeProfileTitleDefaultText),
typeof(string),
typeof(ProfileCard),
new PropertyMetadata(string.Empty, OnDefaultValuePropertyChanged));
/// <summary>
/// Identifies the <see cref="LargeProfileMailDefaultText"/> dependency property.
/// </summary>
public static readonly DependencyProperty LargeProfileMailDefaultTextProperty = DependencyProperty.Register(
nameof(LargeProfileMailDefaultText),
typeof(string),
typeof(ProfileCard),
new PropertyMetadata(string.Empty, OnDefaultValuePropertyChanged));
/// <summary>
/// Identifies the <see cref="NormalMailDefaultText"/> dependency property.
/// </summary>
public static readonly DependencyProperty NormalMailDefaultTextProperty = DependencyProperty.Register(
nameof(NormalMailDefaultText),
typeof(string),
typeof(ProfileCard),
new PropertyMetadata(string.Empty, OnDefaultValuePropertyChanged));
internal static readonly DependencyProperty CurrentProfileItemProperty = DependencyProperty.Register(
nameof(CurrentProfileItem),
typeof(ProfileCardItem),
typeof(ProfileCard),
new PropertyMetadata(new ProfileCardItem()));
/// <summary>
/// Gets or sets user unique identifier.
/// </summary>
public string UserId
{
get { return ((string)GetValue(UserIdProperty))?.Trim(); }
set { SetValue(UserIdProperty, value?.Trim()); }
}
/// <summary>
/// Gets or sets the visual layout of the control. Default is PictureOnly.
/// </summary>
public ViewType DisplayMode
{
get { return (ViewType)GetValue(DisplayModeProperty); }
set { SetValue(DisplayModeProperty, value); }
}
/// <summary>
/// Gets or sets the default image when no user is signed in.
/// </summary>
public BitmapImage DefaultImage
{
get { return (BitmapImage)GetValue(DefaultImageProperty); }
set { SetValue(DefaultImageProperty, value); }
}
/// <summary>
/// Gets or sets the default title text in LargeProfilePhotoLeft mode or LargeProfilePhotoRight mode when no user is signed in.
/// </summary>
public string LargeProfileTitleDefaultText
{
get { return (string)GetValue(LargeProfileTitleDefaultTextProperty); }
set { SetValue(LargeProfileTitleDefaultTextProperty, value); }
}
/// <summary>
/// Gets or sets the default secondary mail text in LargeProfilePhotoLeft mode or LargeProfilePhotoRight mode when no user is signed in.
/// </summary>
public string LargeProfileMailDefaultText
{
get { return (string)GetValue(LargeProfileMailDefaultTextProperty); }
set { SetValue(LargeProfileMailDefaultTextProperty, value); }
}
/// <summary>
/// Gets or sets the default mail text in EmailOnly mode when no user is signed in.
/// </summary>
public string NormalMailDefaultText
{
get { return (string)GetValue(NormalMailDefaultTextProperty); }
set { SetValue(NormalMailDefaultTextProperty, value); }
}
internal ProfileCardItem CurrentProfileItem
{
get { return (ProfileCardItem)GetValue(CurrentProfileItemProperty); }
set { SetValue(CurrentProfileItemProperty, value); }
}
}
}

Просмотреть файл

@ -1,133 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Graph;
using Windows.UI.Core;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The Profile Card control is a simple way to display a user in multiple different formats and mixes of name/image/e-mail.
/// </summary>
public partial class ProfileCard : Control
{
private static readonly BitmapImage PersonPhoto = new BitmapImage(new Uri("ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/person.png"));
private ContentControl _contentPresenter;
/// <summary>
/// Initializes a new instance of the <see cref="ProfileCard"/> class.
/// </summary>
public ProfileCard()
{
DefaultStyleKey = typeof(ProfileCard);
}
/// <summary>
/// Override default OnApplyTemplate to initialize child controls
/// </summary>
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_contentPresenter = GetTemplateChild("ContentPresenter") as ContentControl;
if (_contentPresenter != null)
{
_contentPresenter.ContentTemplateSelector = new ProfileDisplayModeTemplateSelector(_contentPresenter);
}
FetchUserInfo();
}
private async void FetchUserInfo()
{
if (string.IsNullOrEmpty(UserId) || UserId.Equals("Invalid UserId"))
{
InitUserProfile();
}
else
{
GraphServiceClient graphClient = await AadAuthenticationManager.Instance.GetGraphServiceClientAsync();
try
{
var user = await graphClient.Users[UserId].Request().GetAsync();
var profileItem = new ProfileCardItem()
{
NormalMail = user.Mail,
LargeProfileTitle = user.DisplayName,
LargeProfileMail = user.Mail,
DisplayMode = DisplayMode
};
if (string.IsNullOrEmpty(user.Mail))
{
profileItem.UserPhoto = DefaultImage ?? PersonPhoto;
}
else
{
try
{
using (Stream photoStream = await graphClient.Users[UserId].Photo.Content.Request().GetAsync())
using (var ras = photoStream.AsRandomAccessStream())
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(ras);
profileItem.UserPhoto = bitmapImage;
}
}
catch
{
// Swallow error in case of no photo found
profileItem.UserPhoto = DefaultImage ?? PersonPhoto;
}
}
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
CurrentProfileItem = profileItem;
});
}
catch (ServiceException ex)
{
// Swallow error in case of no user id found
if (!ex.Error.Code.Equals("Request_ResourceNotFound"))
{
throw;
}
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
UserId = "Invalid UserId";
});
}
}
}
private void InitUserProfile()
{
var profileItem = new ProfileCardItem()
{
UserPhoto = DefaultImage ?? PersonPhoto,
NormalMail = NormalMailDefaultText ?? string.Empty,
LargeProfileTitle = LargeProfileTitleDefaultText ?? string.Empty,
LargeProfileMail = LargeProfileMailDefaultText ?? string.Empty,
DisplayMode = DisplayMode
};
CurrentProfileItem = profileItem;
}
}
}

Просмотреть файл

@ -1,98 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph"
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters">
<converters:StringVisibilityConverter x:Key="StringVisibilityConverter" />
<Style x:Key="ProfileCardImageBorderStyle"
TargetType="Border">
<Setter Property="Width" Value="80" />
<Setter Property="Height" Value="80" />
</Style>
<Style x:Key="ProfileCardImageEllipseStyle"
TargetType="Ellipse">
<Setter Property="Width" Value="64" />
<Setter Property="Height" Value="64" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="ProfileCardLargeProfileStackPanelStyle"
TargetType="StackPanel">
<Setter Property="Height" Value="80" />
<Setter Property="Orientation" Value="Horizontal" />
</Style>
<Style x:Key="ProfileCardLargeProfileTextBlockStyle"
TargetType="TextBlock">
<Setter Property="FontSize" Value="24" />
<Setter Property="Margin" Value="0 0 0 4" />
</Style>
<Style TargetType="controls:ProfileCard">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Background" Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ProfileCard">
<Grid>
<ContentControl x:Name="ContentPresenter" Content="{TemplateBinding CurrentProfileItem}">
<ContentControl.Resources>
<DataTemplate x:Key="PictureOnly">
<Grid HorizontalAlignment="Left">
<Border Style="{ThemeResource ProfileCardImageBorderStyle}">
<Ellipse Style="{ThemeResource ProfileCardImageEllipseStyle}">
<Ellipse.Fill>
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding UserPhoto}"/>
</Ellipse.Fill>
</Ellipse>
</Border>
</Grid>
</DataTemplate>
<DataTemplate x:Key="EmailOnly">
<Grid HorizontalAlignment="Left">
<TextBlock Text="{Binding NormalMail}" VerticalAlignment="Center" Padding="10 0 10 0"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="LargeProfilePhotoLeft">
<StackPanel Style="{ThemeResource ProfileCardLargeProfileStackPanelStyle}">
<Border Style="{ThemeResource ProfileCardImageBorderStyle}" Margin="0 0 15 0">
<Ellipse Style="{ThemeResource ProfileCardImageEllipseStyle}">
<Ellipse.Fill>
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding UserPhoto}"/>
</Ellipse.Fill>
</Ellipse>
</Border>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding LargeProfileTitle}" Style="{ThemeResource ProfileCardLargeProfileTextBlockStyle}"/>
<TextBlock Text="{Binding LargeProfileMail}" Visibility="{Binding LargeProfileMail, Converter={StaticResource StringVisibilityConverter}}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="LargeProfilePhotoRight">
<StackPanel Style="{ThemeResource ProfileCardLargeProfileStackPanelStyle}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding LargeProfileTitle}" Style="{ThemeResource ProfileCardLargeProfileTextBlockStyle}"/>
<TextBlock Text="{Binding LargeProfileMail}" Visibility="{Binding LargeProfileMail, Converter={StaticResource StringVisibilityConverter}}"/>
</StackPanel>
<Border Style="{ThemeResource ProfileCardImageBorderStyle}" Margin="15 0 0 0">
<Ellipse Style="{ThemeResource ProfileCardImageEllipseStyle}">
<Ellipse.Fill>
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding UserPhoto}"/>
</Ellipse.Fill>
</Ellipse>
</Border>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -1,34 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using Windows.UI.Xaml.Media.Imaging;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
internal class ProfileCardItem
{
public string NormalMail { get; set; }
public string LargeProfileTitle { get; set; }
public string LargeProfileMail { get; set; }
public BitmapImage UserPhoto { get; set; }
public ViewType DisplayMode { get; set; }
public ProfileCardItem Clone()
{
return (ProfileCardItem)MemberwiseClone();
}
}
}

Просмотреть файл

@ -1,63 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
internal class ProfileDisplayModeTemplateSelector : DataTemplateSelector
{
private ContentControl _contentPresenter;
internal ProfileDisplayModeTemplateSelector(ContentControl contentPresenter)
{
_contentPresenter = contentPresenter;
}
private DataTemplate SelectItemTemplate(object item)
{
DataTemplate dataTemplate = null;
if (item != null && item is ProfileCardItem profileItem)
{
switch (profileItem.DisplayMode)
{
case ViewType.EmailOnly:
dataTemplate = _contentPresenter.Resources["EmailOnly"] as DataTemplate;
break;
case ViewType.PictureOnly:
dataTemplate = _contentPresenter.Resources["PictureOnly"] as DataTemplate;
break;
case ViewType.LargeProfilePhotoLeft:
dataTemplate = _contentPresenter.Resources["LargeProfilePhotoLeft"] as DataTemplate;
break;
case ViewType.LargeProfilePhotoRight:
dataTemplate = _contentPresenter.Resources["LargeProfilePhotoRight"] as DataTemplate;
break;
}
}
return dataTemplate;
}
protected override DataTemplate SelectTemplateCore(object item)
{
return SelectItemTemplate(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectItemTemplate(item);
}
}
}

Просмотреть файл

@ -1,40 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The visual layout of the <see cref="ProfileCard"/> control. Default is PictureOnly.
/// </summary>
public enum ViewType
{
/// <summary>
/// Only the user photo is shown.
/// </summary>
PictureOnly = 0,
/// <summary>
/// Only the user email is shown.
/// </summary>
EmailOnly = 1,
/// <summary>
/// A basic user profile is shown, and the user photo is place on the left side.
/// </summary>
LargeProfilePhotoLeft = 2,
/// <summary>
/// A basic user profile is shown, and the user photo is place on the right side.
/// </summary>
LargeProfilePhotoRight = 3
}
}

Просмотреть файл

@ -1,40 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Determines how file details panel is displayed in the <see cref="SharePointFileList"/> control.
/// </summary>
public enum DetailPaneDisplayMode
{
/// <summary>
/// Hide show DetailPane
/// </summary>
Disabled,
/// <summary>
/// Show DetailPane aside
/// </summary>
Side,
/// <summary>
/// Show DetailPane at bottom
/// </summary>
Bottom,
/// <summary>
/// Show DetailPane over list
/// </summary>
Full
}
}

Просмотреть файл

@ -1,68 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using Microsoft.Graph;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Get icon of DriveItem
/// </summary>
internal class DriveItemIconConverter : IValueConverter
{
private static readonly string OfficeIcon = "https://static2.sharepointonline.com/files/fabric/assets/brand-icons/document/png/{0}_32x1_5.png";
private static readonly string LocalIcon = "ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/{0}";
public object Convert(object value, Type targetType, object parameter, string language)
{
DriveItem driveItem = value as DriveItem;
if (driveItem.Folder != null)
{
return string.Format(LocalIcon, "folder.svg");
}
else if (driveItem.File != null)
{
if (driveItem.File.MimeType.StartsWith("image"))
{
return string.Format(LocalIcon, "photo.png");
}
else if (driveItem.File.MimeType.StartsWith("application/vnd.openxmlformats-officedocument"))
{
int index = driveItem.Name.LastIndexOf('.');
if (index != -1)
{
string ext = driveItem.Name.Substring(index + 1);
return string.Format(OfficeIcon, ext);
}
}
}
else if (driveItem.Package != null)
{
switch (driveItem.Package.Type)
{
case "oneNote":
return string.Format(OfficeIcon, "one");
}
}
return string.Format(LocalIcon, "genericfile.png");
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return null;
}
}
}

Просмотреть файл

@ -1,33 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using Microsoft.Graph;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// Arguments relating to a file selected event of SharePointFiles control
/// </summary>
public class FileSelectedEventArgs
{
/// <summary>
/// Gets selected file
/// </summary>
public DriveItem FileSelected { get; private set; }
internal FileSelectedEventArgs(DriveItem fileSelected)
{
FileSelected = fileSelected;
}
}
}

Просмотреть файл

@ -1,32 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using Microsoft.Toolkit.Extensions;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
internal class FileSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
long size = (long)value;
return size.ToFileSizeString();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -1,57 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// All common long extensions should go here
/// </summary>
internal static class Int64Extensions
{
/// <summary>
/// Translate numeric file size to string format.
/// </summary>
/// <param name="size">file size in bytes.</param>
/// <returns>Returns file size string.</returns>
public static string ToFileSizeString(this long size)
{
if (size < 1024)
{
return size.ToString("F0") + " bytes";
}
else if ((size >> 10) < 1024)
{
return (size / (float)1024).ToString("F1") + " KB";
}
else if ((size >> 20) < 1024)
{
return ((size >> 10) / (float)1024).ToString("F1") + " MB";
}
else if ((size >> 30) < 1024)
{
return ((size >> 20) / (float)1024).ToString("F1") + " GB";
}
else if ((size >> 40) < 1024)
{
return ((size >> 30) / (float)1024).ToString("F1") + " TB";
}
else if ((size >> 50) < 1024)
{
return ((size >> 40) / (float)1024).ToString("F1") + " PB";
}
else
{
return ((size >> 50) / (float)1024).ToString("F0") + " EB";
}
}
}
}

Просмотреть файл

@ -1,135 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The SharePointFiles Control displays a simple list of SharePoint Files.
/// </summary>
public partial class SharePointFileList
{
/// <summary>
/// Key of the VisualStateGroup to control nav buttons
/// </summary>
private const string NavStates = "NavStates";
/// <summary>
/// Key of the VisualState when display folder in readonly mode
/// </summary>
private const string NavStatesFolderReadonly = "FolderReadOnly";
/// <summary>
/// Key of the VisualState when display folder in edit mode
/// </summary>
private const string NavStatesFolderEdit = "FolderEdit";
/// <summary>
/// Key of the VisualState when display file in readonly mode
/// </summary>
private const string NavStatesFileReadonly = "FileReadonly";
/// <summary>
/// Key of the VisualState when display file in edit mode
/// </summary>
private const string NavStatesFileEdit = "FileEdit";
/// <summary>
/// Key of the VisualStateGroup to control uploading status
/// </summary>
private const string UploadStatus = "UploadStatus";
/// <summary>
/// Key of the VisualState when not uploading files
/// </summary>
private const string UploadStatusNotUploading = "NotUploading";
/// <summary>
/// Key of the VisualState when uploading files
/// </summary>
private const string UploadStatusUploading = "Uploading";
/// <summary>
/// Key of the VisualState when uploading error occurs
/// </summary>
private const string UploadStatusError = "Error";
/// <summary>
/// Key of the VisualStateGroup to control detail pane
/// </summary>
private const string DetailPaneStates = "DetailPaneStates";
/// <summary>
/// Key of the VisualState when detail pane is hidden
/// </summary>
private const string DetailPaneStatesHide = "Hide";
/// <summary>
/// Key of the VisualState when detail pane is at right side
/// </summary>
private const string DetailPaneStatesSide = "Side";
/// <summary>
/// Key of the VisualState when detail pane is at bottom
/// </summary>
private const string DetailPaneStatesBottom = "Bottom";
/// <summary>
/// Key of the VisualState when detail pane is in full mode
/// </summary>
private const string DetailPaneStatesFull = "Full";
/// <summary>
/// Key of the ListView that contains file list
/// </summary>
private const string ControlFileList = "list";
/// <summary>
/// Key of the back button that contains file list
/// </summary>
private const string ControlBack = "back";
/// <summary>
/// Key of the upload button that contains file list
/// </summary>
private const string ControlUpload = "upload";
/// <summary>
/// Key of the share button that contains file list
/// </summary>
private const string ControlShare = "share";
/// <summary>
/// Key of the download button that contains file list
/// </summary>
private const string ControlDownload = "download";
/// <summary>
/// Key of the delete button that contains file list
/// </summary>
private const string ControlDelete = "delete";
/// <summary>
/// Key of the error button that contains file list
/// </summary>
private const string ControlError = "error";
/// <summary>
/// Key of the cancel button that contains file list
/// </summary>
private const string ControlCancel = "cancel";
/// <summary>
/// Key of the has more button that contains file list
/// </summary>
private const string ControlLoadMore = "hasMore";
}
}

Просмотреть файл

@ -1,270 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Graph;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The SharePointFiles Control displays a simple list of SharePoint Files.
/// </summary>
public partial class SharePointFileList
{
private static async void DriveUrlPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (AadAuthenticationManager.Instance.IsAuthenticated)
{
SharePointFileList control = d as SharePointFileList;
GraphServiceClient graphServiceClient = await AadAuthenticationManager.Instance.GetGraphServiceClientAsync();
if (graphServiceClient != null && !string.IsNullOrWhiteSpace(control.DriveUrl))
{
if (Uri.IsWellFormedUriString(control.DriveUrl, UriKind.Absolute))
{
await control.InitDriveAsync(control.DriveUrl);
}
}
}
}
private static void DetailPanePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SharePointFileList control = d as SharePointFileList;
if (control.IsDetailPaneVisible)
{
control.ShowDetailsPane();
}
}
private async void Back_Click(object sender, RoutedEventArgs e)
{
if (DetailPane == DetailPaneDisplayMode.Full && IsDetailPaneVisible)
{
IsDetailPaneVisible = false;
HideDetailsPane();
}
else if (_driveItemPath.Count > 1)
{
_driveItemPath.Pop();
string parentItemId = _driveItemPath.Peek();
if (_driveItemPath.Count == 1)
{
BackButtonVisibility = Visibility.Collapsed;
}
await LoadFilesAsync(parentItemId);
}
}
private async void Upload_Click(object sender, RoutedEventArgs e)
{
ErrorMessage = string.Empty;
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add("*");
StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
string driveItemId = _driveItemPath.Peek();
using (Stream inputStream = await file.OpenStreamForReadAsync())
{
if (inputStream.Length < 1024 * 1024 * 4)
{
FileUploading++;
StatusMessage = string.Format(UploadingFilesMessageTemplate, FileUploading);
VisualStateManager.GoToState(this, UploadStatusUploading, false);
try
{
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
await graphServiceClient.Drives[_driveId].Items[driveItemId].ItemWithPath(file.Name).Content.Request().PutAsync<DriveItem>(inputStream, _cancelUpload.Token);
VisualStateManager.GoToState(this, UploadStatusNotUploading, false);
FileUploading--;
}
catch (Exception ex)
{
FileUploading--;
ErrorMessage = ex.Message;
VisualStateManager.GoToState(this, UploadStatusError, false);
}
await LoadFilesAsync(driveItemId);
}
}
}
}
private async void Share_Click(object sender, RoutedEventArgs e)
{
if (_list.SelectedItem is DriveItem driveItem)
{
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
Permission link = await graphServiceClient.Drives[_driveId].Items[driveItem.Id].CreateLink("view", "organization").Request().PostAsync();
MessageDialog dialog = new MessageDialog(link.Link.WebUrl, ShareLinkCopiedMessage);
DataPackage package = new DataPackage();
package.SetText(link.Link.WebUrl);
Clipboard.SetContent(package);
await dialog.ShowAsync();
}
}
private async void Download_Click(object sender, RoutedEventArgs e)
{
if (_list.SelectedItem is DriveItem driveItem)
{
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
FileSavePicker picker = new FileSavePicker();
picker.FileTypeChoices.Add(AllFilesMessage, new List<string>() { driveItem.Name.Substring(driveItem.Name.LastIndexOf(".")) });
picker.SuggestedFileName = driveItem.Name;
picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
StorageFile file = await picker.PickSaveFileAsync();
if (file != null)
{
using (Stream inputStream = await graphServiceClient.Drives[_driveId].Items[driveItem.Id].Content.Request().GetAsync())
{
using (Stream outputStream = await file.OpenStreamForWriteAsync())
{
await inputStream.CopyToAsync(outputStream);
}
}
}
}
}
private async void Delete_Click(object sender, RoutedEventArgs e)
{
if (_list.SelectedItem is DriveItem driveItem)
{
MessageDialog confirmDialog = new MessageDialog(DeleteConfirmMessage);
confirmDialog.Commands.Add(new UICommand(DeleteConfirmOkMessage, cmd => { }, commandId: 0));
confirmDialog.Commands.Add(new UICommand(DeleteConfirmCancelMessage, cmd => { }, commandId: 1));
confirmDialog.DefaultCommandIndex = 0;
confirmDialog.CancelCommandIndex = 1;
IUICommand result = await confirmDialog.ShowAsync();
if ((int)result.Id == 0)
{
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
await graphServiceClient.Drives[_driveId].Items[driveItem.Id].Request().DeleteAsync();
string driveItemId = _driveItemPath.Peek();
await LoadFilesAsync(driveItemId);
}
}
}
private async void ShowErrorDetails_Click(object sender, RoutedEventArgs e)
{
MessageDialog messageDialog = new MessageDialog(ErrorMessage);
await messageDialog.ShowAsync();
}
private async void LoadMore_Click(object sender, RoutedEventArgs e)
{
await LoadNextPageAsync();
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
_cancelUpload.Cancel(false);
_cancelUpload.Dispose();
_cancelUpload = new CancellationTokenSource();
}
private async void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_list.SelectedItem is DriveItem driveItem)
{
_cancelGetDetails.Cancel(false);
_cancelGetDetails.Dispose();
_cancelGetDetails = new CancellationTokenSource();
if (driveItem.File != null)
{
try
{
SelectedFile = driveItem;
FileSize = driveItem.Size ?? 0;
LastModified = driveItem.LastModifiedDateTime?.LocalDateTime.ToString() ?? string.Empty;
if (FileSelected != null)
{
FileSelected.Invoke(this, new FileSelectedEventArgs(driveItem));
}
ThumbnailImageSource = null;
VisualStateManager.GoToState(this, NavStatesFileReadonly, false);
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
Task<IDriveItemPermissionsCollectionPage> taskPermissions = graphServiceClient.Drives[_driveId].Items[driveItem.Id].Permissions.Request().GetAsync(_cancelGetDetails.Token);
IDriveItemPermissionsCollectionPage permissions = await taskPermissions;
if (!taskPermissions.IsCanceled)
{
foreach (Permission permission in permissions)
{
if (permission.Roles.Contains("write") || permission.Roles.Contains("owner"))
{
VisualStateManager.GoToState(this, NavStatesFileEdit, false);
break;
}
}
Task<IDriveItemThumbnailsCollectionPage> taskThumbnails = graphServiceClient.Drives[_driveId].Items[driveItem.Id].Thumbnails.Request().GetAsync(_cancelGetDetails.Token);
IDriveItemThumbnailsCollectionPage thumbnails = await taskThumbnails;
if (!taskThumbnails.IsCanceled)
{
ThumbnailSet thumbnailsSet = thumbnails.FirstOrDefault();
if (thumbnailsSet != null)
{
ThumbnailImageSource = new BitmapImage(new Uri(thumbnailsSet.Large.Url));
}
}
IsDetailPaneVisible = true;
ShowDetailsPane();
}
}
catch
{
}
}
else
{
SelectedFile = null;
FileSize = 0;
LastModified = string.Empty;
VisualStateManager.GoToState(this, NavStatesFolderReadonly, false);
IsDetailPaneVisible = false;
HideDetailsPane();
}
}
}
private async void List_ItemClick(object sender, ItemClickEventArgs e)
{
if (e.ClickedItem is DriveItem driveItem && driveItem.Folder != null)
{
_driveItemPath.Push(driveItem.Id);
BackButtonVisibility = Visibility.Visible;
await LoadFilesAsync(driveItem.Id);
}
}
}
}

Просмотреть файл

@ -1,321 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using Microsoft.Graph;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The SharePointFiles Control displays a simple list of SharePoint Files.
/// </summary>
public partial class SharePointFileList
{
/// <summary>
/// Gets required delegated permissions for the <see cref="SharePointFileList"/> control
/// </summary>
public static string[] RequiredDelegatedPermissions
{
get
{
return new string[] { "User.Read", "Files.ReadWrite.All" };
}
}
/// <summary>
/// Url of OneDrive to display
/// </summary>
public static readonly DependencyProperty DriveUrlProperty =
DependencyProperty.Register(
nameof(DriveUrl),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata(string.Empty, DriveUrlPropertyChanged));
/// <summary>
/// How details of a file shows
/// </summary>
public static readonly DependencyProperty DetailPaneProperty =
DependencyProperty.Register(
nameof(DetailPane),
typeof(DetailPaneDisplayMode),
typeof(SharePointFileList),
new PropertyMetadata(DetailPaneDisplayMode.Disabled, DetailPanePropertyChanged));
/// <summary>
/// Page size of each request
/// </summary>
public static readonly DependencyProperty PageSizeProperty =
DependencyProperty.Register(
nameof(PageSize),
typeof(int),
typeof(SharePointFileList),
new PropertyMetadata(20));
/// <summary>
/// Share link copied message
/// </summary>
public static readonly DependencyProperty ShareLinkCopiedMessageProperty =
DependencyProperty.Register(
nameof(ShareLinkCopiedMessage),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata("Link copied!"));
/// <summary>
/// All files message
/// </summary>
public static readonly DependencyProperty AllFilesMessageProperty =
DependencyProperty.Register(
nameof(AllFilesMessage),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata("All Files"));
/// <summary>
/// Delete confirm message
/// </summary>
public static readonly DependencyProperty DeleteConfirmMessageProperty =
DependencyProperty.Register(
nameof(DeleteConfirmMessage),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata("Do you want to delete this file?"));
/// <summary>
/// Delete confirm Ok message
/// </summary>
public static readonly DependencyProperty DeleteConfirmOkMessageProperty =
DependencyProperty.Register(
nameof(DeleteConfirmOkMessage),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata("OK"));
/// <summary>
/// Delete confirm cancel message
/// </summary>
public static readonly DependencyProperty DeleteConfirmCancelMessageProperty =
DependencyProperty.Register(
nameof(DeleteConfirmCancelMessage),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata("Cancel"));
/// <summary>
/// Uploading files message template
/// </summary>
public static readonly DependencyProperty UploadingFilesMessageTemplateProperty =
DependencyProperty.Register(
nameof(UploadingFilesMessageTemplate),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata("Uploading {0} files..."));
internal static readonly DependencyProperty ThumbnailImageSourceProperty =
DependencyProperty.Register(
nameof(ThumbnailImageSource),
typeof(ImageSource),
typeof(SharePointFileList),
new PropertyMetadata(null));
internal static readonly DependencyProperty HasMoreProperty =
DependencyProperty.Register(
nameof(HasMore),
typeof(bool),
typeof(SharePointFileList),
new PropertyMetadata(false));
internal static readonly DependencyProperty SelectedFileProperty =
DependencyProperty.Register(
nameof(SelectedFile),
typeof(DriveItem),
typeof(SharePointFileList),
new PropertyMetadata(null));
internal static readonly DependencyProperty SizeProperty =
DependencyProperty.Register(
nameof(FileSize),
typeof(long),
typeof(SharePointFileList),
new PropertyMetadata(0L));
internal static readonly DependencyProperty LastModifiedProperty =
DependencyProperty.Register(
nameof(LastModified),
typeof(string),
typeof(SharePointFileList),
null);
internal static readonly DependencyProperty BackButtonVisibilityProperty =
DependencyProperty.Register(
nameof(BackButtonVisibility),
typeof(Visibility),
typeof(SharePointFileList),
new PropertyMetadata(Visibility.Collapsed));
internal static readonly DependencyProperty StatusMessageProperty =
DependencyProperty.Register(
nameof(StatusMessage),
typeof(string),
typeof(SharePointFileList),
new PropertyMetadata(string.Empty));
private static readonly DependencyProperty IsDetailPaneVisibleProperty =
DependencyProperty.Register(
nameof(IsDetailPaneVisible),
typeof(bool),
typeof(SharePointFileList),
new PropertyMetadata(false));
/// <summary>
/// Gets or sets drive or SharePoint document library URL to display
/// </summary>
public string DriveUrl
{
get { return ((string)GetValue(DriveUrlProperty))?.Trim(); }
set { SetValue(DriveUrlProperty, value?.Trim()); }
}
/// <summary>
/// Gets or sets how DetailPane shows
/// </summary>
public DetailPaneDisplayMode DetailPane
{
get { return (DetailPaneDisplayMode)GetValue(DetailPaneProperty); }
set { SetValue(DetailPaneProperty, value); }
}
/// <summary>
/// Gets or sets page size of each request
/// </summary>
public int PageSize
{
get { return (int)GetValue(PageSizeProperty); }
set { SetValue(PageSizeProperty, value); }
}
/// <summary>
/// Gets or sets the message when share link copied
/// </summary>
public string ShareLinkCopiedMessage
{
get { return (string)GetValue(ShareLinkCopiedMessageProperty); }
set { SetValue(ShareLinkCopiedMessageProperty, value); }
}
/// <summary>
/// Gets or sets the label of All Files
/// </summary>
public string AllFilesMessage
{
get { return (string)GetValue(AllFilesMessageProperty); }
set { SetValue(AllFilesMessageProperty, value); }
}
/// <summary>
/// Gets or sets the message of delete confirm dialog
/// </summary>
public string DeleteConfirmMessage
{
get { return (string)GetValue(DeleteConfirmMessageProperty); }
set { SetValue(DeleteConfirmMessageProperty, value); }
}
/// <summary>
/// Gets or sets the caption of ok button in delete confirm dialog
/// </summary>
public string DeleteConfirmOkMessage
{
get { return (string)GetValue(DeleteConfirmOkMessageProperty); }
set { SetValue(DeleteConfirmOkMessageProperty, value); }
}
/// <summary>
/// Gets or sets the caption of cancel button in delete confirm dialog
/// </summary>
public string DeleteConfirmCancelMessage
{
get { return (string)GetValue(DeleteConfirmCancelMessageProperty); }
set { SetValue(DeleteConfirmCancelMessageProperty, value); }
}
/// <summary>
/// Gets or sets the template of uploading files
/// </summary>
public string UploadingFilesMessageTemplate
{
get { return (string)GetValue(UploadingFilesMessageTemplateProperty); }
set { SetValue(UploadingFilesMessageTemplateProperty, value); }
}
internal bool HasMore
{
get { return (bool)GetValue(HasMoreProperty); }
set { SetValue(HasMoreProperty, value); }
}
internal DriveItem SelectedFile
{
get { return (DriveItem)GetValue(SelectedFileProperty); }
set { SetValue(SelectedFileProperty, value); }
}
internal long FileSize
{
get { return (long)GetValue(SizeProperty); }
set { SetValue(SizeProperty, value); }
}
internal string LastModified
{
get { return (string)GetValue(LastModifiedProperty); }
set { SetValue(LastModifiedProperty, value); }
}
internal ImageSource ThumbnailImageSource
{
get { return (ImageSource)GetValue(ThumbnailImageSourceProperty); }
set { SetValue(ThumbnailImageSourceProperty, value); }
}
internal string StatusMessage
{
get { return (string)GetValue(StatusMessageProperty); }
set { SetValue(StatusMessageProperty, value); }
}
internal Visibility BackButtonVisibility
{
get { return (Visibility)GetValue(BackButtonVisibilityProperty); }
set { SetValue(BackButtonVisibilityProperty, value); }
}
private bool IsDetailPaneVisible
{
get
{
return (bool)GetValue(IsDetailPaneVisibleProperty);
}
set
{
SetValue(IsDetailPaneVisibleProperty, value);
}
}
private int FileUploading { get; set; }
private string ErrorMessage { get; set; }
}
}

Просмотреть файл

@ -1,335 +0,0 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Graph;
using Newtonsoft.Json;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
{
/// <summary>
/// The SharePointFiles Control displays a simple list of SharePoint Files.
/// </summary>
[TemplatePart(Name = ControlFileList, Type = typeof(ListView))]
[TemplatePart(Name = ControlBack, Type = typeof(Button))]
[TemplatePart(Name = ControlCancel, Type = typeof(Button))]
[TemplatePart(Name = ControlDelete, Type = typeof(Button))]
[TemplatePart(Name = ControlDownload, Type = typeof(Button))]
[TemplatePart(Name = ControlLoadMore, Type = typeof(Button))]
[TemplatePart(Name = ControlShare, Type = typeof(Button))]
[TemplatePart(Name = ControlUpload, Type = typeof(Button))]
[TemplatePart(Name = ControlError, Type = typeof(HyperlinkButton))]
[TemplateVisualState(Name = UploadStatusNotUploading, GroupName = UploadStatus)]
[TemplateVisualState(Name = UploadStatusUploading, GroupName = UploadStatus)]
[TemplateVisualState(Name = UploadStatusError, GroupName = UploadStatus)]
[TemplateVisualState(Name = DetailPaneStatesHide, GroupName = DetailPaneStates)]
[TemplateVisualState(Name = DetailPaneStatesSide, GroupName = DetailPaneStates)]
[TemplateVisualState(Name = DetailPaneStatesBottom, GroupName = DetailPaneStates)]
[TemplateVisualState(Name = DetailPaneStatesFull, GroupName = DetailPaneStates)]
[TemplateVisualState(Name = NavStatesFolderReadonly, GroupName = NavStates)]
[TemplateVisualState(Name = NavStatesFolderEdit, GroupName = NavStates)]
[TemplateVisualState(Name = NavStatesFileReadonly, GroupName = NavStates)]
[TemplateVisualState(Name = NavStatesFileEdit, GroupName = NavStates)]
public partial class SharePointFileList : Control
{
/// <summary>
/// File is selected
/// </summary>
public event EventHandler<FileSelectedEventArgs> FileSelected;
private string _driveId;
private Stack<string> _driveItemPath = new Stack<string>();
private IDriveItemChildrenCollectionRequest _nextPageRequest = null;
private CancellationTokenSource _cancelUpload = new CancellationTokenSource();
private CancellationTokenSource _cancelLoadFile = new CancellationTokenSource();
private CancellationTokenSource _cancelGetDetails = new CancellationTokenSource();
private AadAuthenticationManager _aadAuthenticationManager = AadAuthenticationManager.Instance;
private ListView _list;
/// <summary>
/// Initializes a new instance of the <see cref="SharePointFileList"/> class.
/// </summary>
public SharePointFileList()
{
DefaultStyleKey = typeof(SharePointFileList);
}
/// <summary>
/// Called when applying the control template.
/// </summary>
protected override void OnApplyTemplate()
{
_list = GetTemplateChild(ControlFileList) as ListView;
if (_list != null)
{
_list.SelectionChanged += List_SelectionChanged;
_list.ItemClick += List_ItemClick;
}
Button back = GetTemplateChild(ControlBack) as Button;
if (back != null)
{
back.Click += Back_Click;
}
Button cancel = GetTemplateChild(ControlCancel) as Button;
if (cancel != null)
{
cancel.Click += Cancel_Click;
}
Button delete = GetTemplateChild(ControlDelete) as Button;
if (delete != null)
{
delete.Click += Delete_Click;
}
Button download = GetTemplateChild(ControlDownload) as Button;
if (download != null)
{
download.Click += Download_Click;
}
Button loadMore = GetTemplateChild(ControlLoadMore) as Button;
if (loadMore != null)
{
loadMore.Click += LoadMore_Click;
}
Button share = GetTemplateChild(ControlShare) as Button;
if (share != null)
{
share.Click += Share_Click;
}
Button upload = GetTemplateChild(ControlUpload) as Button;
if (upload != null)
{
upload.Click += Upload_Click;
}
HyperlinkButton error = GetTemplateChild(ControlError) as HyperlinkButton;
if (error != null)
{
error.Click += ShowErrorDetails_Click;
}
base.OnApplyTemplate();
}
/// <summary>
/// Retrieves an appropriate Drive URL from a SharePoint document library root URL
/// </summary>
/// <param name="rawDocLibUrl">Raw URL for SharePoint document library</param>
/// <returns>Drive URL</returns>
public async Task<string> GetDriveUrlFromSharePointUrlAsync(string rawDocLibUrl)
{
if (string.IsNullOrEmpty(rawDocLibUrl))
{
return rawDocLibUrl;
}
rawDocLibUrl = WebUtility.UrlDecode(rawDocLibUrl);
Match match = Regex.Match(rawDocLibUrl, @"(https?://([^/]+)((/[^/?]+)*?)(/[^/?]+))(/(Forms/\w+.aspx)?)?(\?.*)?$", RegexOptions.IgnoreCase);
string docLibUrl = match.Groups[1].Value;
string hostName = match.Groups[2].Value;
string siteRelativePath = match.Groups[3].Value;
if (string.IsNullOrEmpty(siteRelativePath))
{
siteRelativePath = "/";
}
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
Site site = await graphServiceClient.Sites.GetByPath(siteRelativePath, hostName).Request().GetAsync();
ISiteDrivesCollectionPage drives = await graphServiceClient.Sites[site.Id].Drives.Request().GetAsync();
Drive drive = drives.SingleOrDefault(o => WebUtility.UrlDecode(o.WebUrl).Equals(docLibUrl, StringComparison.CurrentCultureIgnoreCase));
if (drive == null)
{
throw new Exception("Drive not found");
}
return graphServiceClient.Drives[drive.Id].RequestUrl;
}
private async Task InitDriveAsync(string driveUrl)
{
try
{
string realDriveURL;
if (driveUrl.StartsWith("https://graph.microsoft.com/", StringComparison.CurrentCultureIgnoreCase))
{
realDriveURL = driveUrl;
}
else
{
realDriveURL = await GetDriveUrlFromSharePointUrlAsync(driveUrl);
}
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, realDriveURL);
await graphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(message);
HttpResponseMessage result = await graphServiceClient.HttpProvider.SendAsync(message);
if (result.StatusCode == HttpStatusCode.OK)
{
string json = await result.Content.ReadAsStringAsync();
Drive drive = JsonConvert.DeserializeObject<Drive>(json);
if (drive != null)
{
_driveId = drive.Id;
_driveItemPath.Clear();
DriveItem rootDriveItem = await graphServiceClient.Drives[_driveId].Root.Request().GetAsync();
_driveItemPath.Push(rootDriveItem.Id);
await LoadFilesAsync(rootDriveItem.Id);
BackButtonVisibility = Visibility.Collapsed;
}
}
}
catch (Exception)
{
}
}
private async Task LoadFilesAsync(string driveItemId, int pageIndex = 0)
{
IsDetailPaneVisible = false;
HideDetailsPane();
if (!string.IsNullOrEmpty(_driveId))
{
try
{
_cancelLoadFile.Cancel(false);
_cancelLoadFile.Dispose();
_cancelLoadFile = new CancellationTokenSource();
_list.Items.Clear();
VisualStateManager.GoToState(this, NavStatesFolderReadonly, false);
QueryOption queryOption = new QueryOption("$top", PageSize.ToString());
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
Task<IDriveItemChildrenCollectionPage> taskFiles = graphServiceClient.Drives[_driveId].Items[driveItemId].Children.Request(new List<Option> { queryOption }).GetAsync(_cancelLoadFile.Token);
IDriveItemChildrenCollectionPage files = await taskFiles;
if (!taskFiles.IsCanceled)
{
_list.Items.Clear();
foreach (DriveItem file in files)
{
_list.Items.Add(file);
}
_nextPageRequest = files.NextPageRequest;
HasMore = _nextPageRequest != null;
VisualStateManager.GoToState(this, NavStatesFolderReadonly, false);
if (_driveItemPath.Count > 1)
{
IDriveItemPermissionsCollectionPage permissions = await graphServiceClient.Drives[_driveId].Items[driveItemId].Permissions.Request().GetAsync();
foreach (Permission permission in permissions)
{
if (permission.Roles.Contains("write") || permission.Roles.Contains("owner"))
{
VisualStateManager.GoToState(this, NavStatesFolderEdit, false);
break;
}
}
}
else
{
VisualStateManager.GoToState(this, NavStatesFolderEdit, false);
}
}
if (_list.Items.Count > 0)
{
_list.SelectedIndex = 0;
}
}
catch (Exception)
{
}
}
}
private async Task LoadNextPageAsync()
{
try
{
if (_nextPageRequest != null)
{
Task<IDriveItemChildrenCollectionPage> taskItems = _nextPageRequest.GetAsync(_cancelLoadFile.Token);
IDriveItemChildrenCollectionPage items = await taskItems;
if (!taskItems.IsCanceled)
{
foreach (DriveItem item in items)
{
_list.Items.Add(item);
}
_nextPageRequest = items.NextPageRequest;
HasMore = _nextPageRequest != null;
}
}
}
catch
{
}
}
private void HideDetailsPane()
{
VisualStateManager.GoToState(this, DetailPaneStatesHide, false);
if (_driveItemPath.Count <= 1)
{
BackButtonVisibility = Visibility.Collapsed;
}
}
private void ShowDetailsPane()
{
switch (DetailPane)
{
case DetailPaneDisplayMode.Side:
if (_driveItemPath.Count <= 1)
{
BackButtonVisibility = Visibility.Collapsed;
}
VisualStateManager.GoToState(this, DetailPaneStatesSide, false);
break;
case DetailPaneDisplayMode.Bottom:
if (_driveItemPath.Count <= 1)
{
BackButtonVisibility = Visibility.Collapsed;
}
VisualStateManager.GoToState(this, DetailPaneStatesBottom, false);
break;
case DetailPaneDisplayMode.Full:
BackButtonVisibility = Visibility.Visible;
VisualStateManager.GoToState(this, DetailPaneStatesFull, false);
break;
default:
HideDetailsPane();
break;
}
}
}
}

Просмотреть файл

@ -1,325 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph">
<local:DriveItemIconConverter x:Key="DriveItemIconConverter" />
<local:FileSizeConverter x:Key="FileSizeConverter" />
<Style x:Name="MetaLabel"
TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="10,5,10,0" />
</Style>
<Style x:Name="MetaValue"
TargetType="TextBlock">
<Setter Property="Margin" Value="10,5" />
</Style>
<Style x:Name="MetaValueLink"
TargetType="HyperlinkButton">
<Setter Property="Margin" Value="10,5" />
</Style>
<Style x:Name="MetaValueProfile"
TargetType="local:ProfileCard">
<Setter Property="Margin" Value="10,5" />
</Style>
<Style x:Name="ToolbarButton"
TargetType="Button">
<Setter Property="Height" Value="48" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style x:Name="ToolbarButtonImage"
TargetType="Image">
<Setter Property="Stretch" Value="Uniform" />
</Style>
<Style TargetType="local:SharePointFileList">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SharePointFileList">
<Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="3*" />
<RowDefinition Height="4*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.ColumnSpan="3"
Margin="12,0,0,0"
Orientation="Horizontal">
<Button x:Name="back"
AutomationProperties.Name="Back"
Style="{StaticResource ToolbarButton}"
Visibility="{TemplateBinding BackButtonVisibility}">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="Back" />
<TextBlock Margin="5,0,0,0"
VerticalAlignment="Center"
Text="Back" />
</StackPanel>
</Button>
<Button Name="upload"
AutomationProperties.Name="Upload a new file"
Style="{StaticResource ToolbarButton}"
Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="Upload" />
<TextBlock Margin="5,0,0,0"
VerticalAlignment="Center"
Text="Upload" />
</StackPanel>
</Button>
<Button Name="share"
AutomationProperties.Name="Get share link"
Style="{StaticResource ToolbarButton}"
Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="Share" />
<TextBlock Margin="5,0,0,0"
VerticalAlignment="Center"
Text="Share" />
</StackPanel>
</Button>
<Button Name="download"
AutomationProperties.Name="Download selected file"
Style="{StaticResource ToolbarButton}"
Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="Download" />
<TextBlock Margin="5,0,0,0"
VerticalAlignment="Center"
Text="Download" />
</StackPanel>
</Button>
<Button Name="delete"
AutomationProperties.Name="Delete selected file"
Style="{StaticResource ToolbarButton}"
Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="Delete" />
<TextBlock Margin="5,0,0,0"
VerticalAlignment="Center"
Text="Delete" />
</StackPanel>
</Button>
<TextBlock Name="status"
VerticalAlignment="Center"
Text="{TemplateBinding StatusMessage}" />
<HyperlinkButton Name="error"
VerticalAlignment="Center"
AutomationProperties.Name="Show error message"
Content="Errors adding files."
Visibility="Collapsed" />
<Button Name="cancel"
AutomationProperties.Name="Cancel uploading"
Style="{StaticResource ToolbarButton}"
Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="Cancel" />
<TextBlock Margin="5,0,0,0"
VerticalAlignment="Center"
Text="Cancel" />
</StackPanel>
</Button>
</StackPanel>
<ListView x:Name="list"
Grid.Row="1"
Grid.RowSpan="3"
Grid.ColumnSpan="3"
AutomationProperties.Name="List"
IsItemClickEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Height="60"
AutomationProperties.Name="{Binding Path=Name}"
Orientation="Horizontal">
<Image Width="32"
Height="32"
Margin="0,10,10,10"
Source="{Binding Converter={StaticResource DriveItemIconConverter}}" />
<TextBlock VerticalAlignment="Center"
Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Footer>
<Button x:Name="hasMore"
Width="Auto"
HorizontalAlignment="Stretch"
AutomationProperties.Name="Load more items"
BorderThickness="0"
Style="{StaticResource ToolbarButton}"
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=HasMore}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,5,0"
VerticalAlignment="Center"
Text="Load More" />
<SymbolIcon Symbol="More" />
</StackPanel>
</Button>
</ListView.Footer>
</ListView>
<Grid x:Name="thumbnail"
Grid.Row="1"
Grid.Column="2"
Padding="5"
Background="{ThemeResource SystemBaseMediumColor}"
Visibility="Collapsed">
<Image Source="{TemplateBinding ThumbnailImageSource}" />
</Grid>
<ScrollViewer x:Name="details"
Background="{ThemeResource SystemBaseLowColor}"
Visibility="Collapsed">
<StackPanel>
<TextBlock Style="{StaticResource MetaLabel}">Name</TextBlock>
<HyperlinkButton NavigateUri="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectedFile.WebUrl}"
Style="{StaticResource MetaValueLink}">
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectedFile.Name}"
TextWrapping="Wrap" />
</HyperlinkButton>
<TextBlock Style="{StaticResource MetaLabel}">Size</TextBlock>
<TextBlock Style="{StaticResource MetaValue}"
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=FileSize, Converter={StaticResource FileSizeConverter}}" />
<TextBlock Style="{StaticResource MetaLabel}">Last Modified</TextBlock>
<TextBlock Style="{StaticResource MetaValue}"
Text="{TemplateBinding LastModified}" />
<TextBlock Style="{StaticResource MetaLabel}">Last Modified By</TextBlock>
<local:ProfileCard DisplayMode="LargeProfilePhotoLeft"
Style="{StaticResource MetaValueProfile}"
UserId="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectedFile.LastModifiedBy.User.Id}" />
</StackPanel>
</ScrollViewer>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="NavStates">
<VisualState x:Name="FolderReadonly">
<VisualState.Setters>
<Setter Target="upload.Visibility" Value="Collapsed" />
<Setter Target="share.Visibility" Value="Collapsed" />
<Setter Target="download.Visibility" Value="Collapsed" />
<Setter Target="delete.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="FolderEdit">
<VisualState.Setters>
<Setter Target="upload.Visibility" Value="Visible" />
<Setter Target="share.Visibility" Value="Collapsed" />
<Setter Target="download.Visibility" Value="Collapsed" />
<Setter Target="delete.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="FileReadonly">
<VisualState.Setters>
<Setter Target="share.Visibility" Value="Collapsed" />
<Setter Target="download.Visibility" Value="Visible" />
<Setter Target="delete.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="FileEdit">
<VisualState.Setters>
<Setter Target="share.Visibility" Value="Visible" />
<Setter Target="download.Visibility" Value="Visible" />
<Setter Target="delete.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="UploadStatus">
<VisualState x:Name="NotUploading">
<VisualState.Setters>
<Setter Target="status.Visibility" Value="Collapsed" />
<Setter Target="error.Visibility" Value="Collapsed" />
<Setter Target="cancel.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Uploading">
<VisualState.Setters>
<Setter Target="status.Visibility" Value="Visible" />
<Setter Target="error.Visibility" Value="Collapsed" />
<Setter Target="cancel.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Error">
<VisualState.Setters>
<Setter Target="status.Visibility" Value="Collapsed" />
<Setter Target="error.Visibility" Value="Visible" />
<Setter Target="cancel.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="DetailPaneStates">
<VisualState x:Name="Hide">
<VisualState.Setters>
<Setter Target="list.Visibility" Value="Visible" />
<Setter Target="list.(Grid.RowSpan)" Value="3" />
<Setter Target="list.(Grid.ColumnSpan)" Value="3" />
<Setter Target="thumbnail.Visibility" Value="Collapsed" />
<Setter Target="details.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Side">
<VisualState.Setters>
<Setter Target="list.Visibility" Value="Visible" />
<Setter Target="list.(Grid.RowSpan)" Value="3" />
<Setter Target="list.(Grid.ColumnSpan)" Value="2" />
<Setter Target="thumbnail.Visibility" Value="Visible" />
<Setter Target="thumbnail.(Grid.Row)" Value="1" />
<Setter Target="thumbnail.(Grid.RowSpan)" Value="1" />
<Setter Target="thumbnail.(Grid.Column)" Value="2" />
<Setter Target="thumbnail.(Grid.ColumnSpan)" Value="1" />
<Setter Target="details.Visibility" Value="Visible" />
<Setter Target="details.(Grid.Row)" Value="2" />
<Setter Target="details.(Grid.RowSpan)" Value="2" />
<Setter Target="details.(Grid.Column)" Value="2" />
<Setter Target="details.(Grid.ColumnSpan)" Value="1" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Bottom">
<VisualState.Setters>
<Setter Target="list.Visibility" Value="Visible" />
<Setter Target="list.(Grid.RowSpan)" Value="2" />
<Setter Target="list.(Grid.ColumnSpan)" Value="3" />
<Setter Target="thumbnail.Visibility" Value="Visible" />
<Setter Target="thumbnail.(Grid.Row)" Value="3" />
<Setter Target="thumbnail.(Grid.RowSpan)" Value="1" />
<Setter Target="thumbnail.(Grid.Column)" Value="0" />
<Setter Target="thumbnail.(Grid.ColumnSpan)" Value="1" />
<Setter Target="details.Visibility" Value="Visible" />
<Setter Target="details.(Grid.Row)" Value="3" />
<Setter Target="details.(Grid.RowSpan)" Value="1" />
<Setter Target="details.(Grid.Column)" Value="1" />
<Setter Target="details.(Grid.ColumnSpan)" Value="2" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Full">
<VisualState.Setters>
<Setter Target="list.Visibility" Value="Collapsed" />
<Setter Target="thumbnail.Visibility" Value="Visible" />
<Setter Target="thumbnail.(Grid.Row)" Value="1" />
<Setter Target="thumbnail.(Grid.RowSpan)" Value="3" />
<Setter Target="thumbnail.(Grid.Column)" Value="0" />
<Setter Target="thumbnail.(Grid.ColumnSpan)" Value="1" />
<Setter Target="details.Visibility" Value="Visible" />
<Setter Target="details.(Grid.Row)" Value="1" />
<Setter Target="details.(Grid.RowSpan)" Value="3" />
<Setter Target="details.(Grid.Column)" Value="1" />
<Setter Target="details.(Grid.ColumnSpan)" Value="2" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -22,9 +22,6 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.Services", "Microsoft.Toolkit.Uwp.Services\Microsoft.Toolkit.Uwp.Services.csproj", "{7189A42D-6F1A-4FA3-8E00-E2C14FDF167A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Controls", "Microsoft.Toolkit.Uwp.UI.Controls\Microsoft.Toolkit.Uwp.UI.Controls.csproj", "{E9FAABFB-D726-42C1-83C1-CB46A29FEA81}"
ProjectSection(ProjectDependencies) = postProject
{34398053-FC70-4243-84F9-F355DEFFF66D} = {34398053-FC70-4243-84F9-F355DEFFF66D}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notifications", "Notifications", "{9333C63A-F64F-4797-82B3-017422668A5D}"
EndProject
@ -91,6 +88,10 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GazeInputTest", "GazeInputTest\GazeInputTest.csproj", "{A122EA02-4DE7-413D-BFBF-AF7DFC668DD6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Controls.Graph", "Microsoft.Toolkit.Uwp.UI.Controls.Graph\Microsoft.Toolkit.Uwp.UI.Controls.Graph.csproj", "{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}"
ProjectSection(ProjectDependencies) = postProject
{34398053-FC70-4243-84F9-F355DEFFF66D} = {34398053-FC70-4243-84F9-F355DEFFF66D}
{3DD8AA7C-3569-4E51-992F-0C2257E8878E} = {3DD8AA7C-3569-4E51-992F-0C2257E8878E}
EndProjectSection
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
@ -686,13 +687,9 @@ Global
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Debug|x86.ActiveCfg = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Debug|x86.Build.0 = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|Any CPU.ActiveCfg = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|Any CPU.Build.0 = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|ARM.ActiveCfg = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|ARM.Build.0 = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x64.ActiveCfg = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x64.Build.0 = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x86.ActiveCfg = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x86.Build.0 = Debug|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|ARM.ActiveCfg = Release|Any CPU