diff --git a/CommunityToolkit.Graph.Uwp/Extensions/ElementExtensions.IsVisibleWhen.cs b/CommunityToolkit.Graph.Uwp/Extensions/ElementExtensions.IsVisibleWhen.cs new file mode 100644 index 0000000..f19347d --- /dev/null +++ b/CommunityToolkit.Graph.Uwp/Extensions/ElementExtensions.IsVisibleWhen.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Concurrent; +using CommunityToolkit.Authentication; +using Windows.UI.Xaml; + +namespace CommunityToolkit.Graph.Uwp +{ + /// + /// IsVisibleWhen extension on FrameworkElement for decaring element visibility behavior in response to authentication changes. + /// + public static partial class ElementExtensions + { + private static readonly object _updateLock = new (); + private static readonly ConcurrentDictionary _listeningElements = new (); + + private static readonly DependencyProperty _isVisibleWhenProperty = + DependencyProperty.RegisterAttached("IsVisibleWhen", typeof(ProviderState), typeof(FrameworkElement), new PropertyMetadata(null, OnIsVisibleWhenPropertyChanged)); + + static ElementExtensions() + { + ProviderManager.Instance.ProviderUpdated += OnProviderUpdated; + } + + /// + /// Sets a value indicating whether an element should update its visibility based on provider state changes. + /// + /// The target element. + /// The state in which to be visible. + public static void SetIsVisibleWhen(FrameworkElement element, ProviderState value) + { + element.SetValue(_isVisibleWhenProperty, value); + } + + /// + /// Gets a value indicating whether an element should update its visibility based on provider state changes. + /// + /// The target element. + /// The state in which to be visible. + public static ProviderState GetIsVisibleWhen(FrameworkElement element) + { + return (ProviderState)element.GetValue(_isVisibleWhenProperty); + } + + private static void OnIsVisibleWhenPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is FrameworkElement element) + { + if (e.NewValue is ProviderState newState) + { + RegisterElement(element, newState); + } + else + { + DeregisterElement(element); + } + + var providerState = ProviderManager.Instance.GlobalProvider?.State; + UpdateElementVisibility(element, providerState); + } + } + + private static void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) + { + lock (_updateLock) + { + var providerState = ProviderManager.Instance.GlobalProvider?.State; + foreach (var kvp in _listeningElements) + { + UpdateElementVisibility(kvp.Key, providerState); + } + } + } + + private static void OnElementUnloaded(object sender, RoutedEventArgs e) + { + if (sender is FrameworkElement element) + { + DeregisterElement(element); + } + } + + private static void RegisterElement(FrameworkElement element, ProviderState providerState) + { + element.Unloaded += OnElementUnloaded; + _listeningElements.TryAdd(element, providerState); + } + + private static void DeregisterElement(FrameworkElement element) + { + element.Unloaded -= OnElementUnloaded; + _listeningElements.TryRemove(element, out ProviderState providerState); + } + + private static void UpdateElementVisibility(FrameworkElement element, ProviderState? state) + { + var isVisibleWhen = GetIsVisibleWhen(element); + + element.Visibility = isVisibleWhen == state ? Visibility.Visible : Visibility.Collapsed; + } + } +}