-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement ActivityIndicatorHandler in WinUI (#761)
* Implement ActivityIndicatorHandler in WinUI * Fix build error * Enable nullable in ActivityIndicatorExtensions * Added nullable enable flag in WinUI ActivityIndicatorHandler * Fix build error * Apply suggestions from code review Co-authored-by: Hadrian Tang <hadrianwttang@outlook.com> * Fix merge * Fixed ResourceDictionary error * Move extensions to be internal Co-authored-by: Rui Marinho <me@ruimarinho.net> Co-authored-by: Hadrian Tang <hadrianwttang@outlook.com>
- Loading branch information
1 parent
2216517
commit 4641d1d
Showing
10 changed files
with
635 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 24 additions & 9 deletions
33
src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.Windows.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,31 @@ | ||
using System; | ||
using Microsoft.UI.Xaml.Controls; | ||
|
||
#nullable enable | ||
namespace Microsoft.Maui.Handlers | ||
{ | ||
public partial class ActivityIndicatorHandler : ViewHandler<IActivityIndicator, ProgressBar> | ||
public partial class ActivityIndicatorHandler : ViewHandler<IActivityIndicator, MauiActivityIndicator> | ||
{ | ||
protected override ProgressBar CreateNativeView() => new ProgressBar(); | ||
object? _foregroundDefault; | ||
|
||
protected override MauiActivityIndicator CreateNativeView() => new MauiActivityIndicator | ||
{ | ||
IsIndeterminate = true, | ||
Style = UI.Xaml.Application.Current.Resources["MauiActivityIndicatorStyle"] as UI.Xaml.Style | ||
}; | ||
|
||
protected override void SetupDefaults(MauiActivityIndicator nativeView) | ||
{ | ||
_foregroundDefault = nativeView.GetForegroundCache(); | ||
|
||
base.SetupDefaults(nativeView); | ||
} | ||
|
||
[MissingMapper] | ||
public static void MapIsRunning(ActivityIndicatorHandler handler, IActivityIndicator activityIndicator) { } | ||
public static void MapIsRunning(ActivityIndicatorHandler handler, IActivityIndicator activityIndicator) | ||
{ | ||
handler.NativeView?.UpdateIsRunning(activityIndicator); | ||
} | ||
|
||
[MissingMapper] | ||
public static void MapColor(ActivityIndicatorHandler handler, IActivityIndicator activityIndicator) { } | ||
public static void MapColor(ActivityIndicatorHandler handler, IActivityIndicator activityIndicator) | ||
{ | ||
handler.NativeView?.UpdateColor(activityIndicator, handler._foregroundDefault); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#nullable enable | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
namespace Microsoft.Maui | ||
{ | ||
internal static class ReflectionExtensions | ||
{ | ||
public static FieldInfo? GetField(this Type type, Func<FieldInfo, bool> predicate) | ||
{ | ||
return GetFields(type).FirstOrDefault(predicate); | ||
} | ||
|
||
public static FieldInfo? GetField(this Type type, string name) | ||
{ | ||
return type.GetField(fi => fi.Name == name); | ||
} | ||
|
||
public static IEnumerable<FieldInfo> GetFields(this Type type) | ||
{ | ||
return GetParts(type, i => i.DeclaredFields); | ||
} | ||
|
||
public static IEnumerable<PropertyInfo> GetProperties(this Type type) | ||
{ | ||
return GetParts(type, ti => ti.DeclaredProperties); | ||
} | ||
|
||
public static PropertyInfo? GetProperty(this Type type, string name) | ||
{ | ||
Type? t = type; | ||
while (t != null) | ||
{ | ||
TypeInfo ti = t.GetTypeInfo(); | ||
PropertyInfo? property = ti.GetDeclaredProperty(name); | ||
|
||
if (property != null) | ||
return property; | ||
|
||
t = ti.BaseType; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
internal static object[]? GetCustomAttributesSafe(this Assembly assembly, Type attrType) | ||
{ | ||
try | ||
{ | ||
#if !NETSTANDARD1_0 | ||
return assembly.GetCustomAttributes(attrType, true); | ||
#else | ||
return assembly.GetCustomAttributes(attrType).ToArray(); | ||
#endif | ||
} | ||
catch (FileNotFoundException) | ||
{ | ||
// Sometimes the previewer doesn't actually have everything required for these loads to work | ||
// TODO: Register the exception in the Log when we have the Logger ported | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public static Type[] GetExportedTypes(this Assembly assembly) | ||
{ | ||
return assembly.ExportedTypes.ToArray(); | ||
} | ||
|
||
public static bool IsAssignableFrom(this Type self, Type c) | ||
{ | ||
return self.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); | ||
} | ||
|
||
public static bool IsInstanceOfType(this Type self, object o) | ||
{ | ||
return self.GetTypeInfo().IsAssignableFrom(o.GetType().GetTypeInfo()); | ||
} | ||
|
||
static IEnumerable<T> GetParts<T>(Type type, Func<TypeInfo, IEnumerable<T>> selector) | ||
{ | ||
Type? t = type; | ||
while (t != null) | ||
{ | ||
TypeInfo ti = t.GetTypeInfo(); | ||
foreach (T f in selector(ti)) | ||
yield return f; | ||
t = ti.BaseType; | ||
} | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
src/Core/src/Platform/Windows/ActivityIndicatorExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#nullable enable | ||
using Microsoft.Maui.Graphics; | ||
|
||
namespace Microsoft.Maui | ||
{ | ||
public static class ActivityIndicatorExtensions | ||
{ | ||
public static void UpdateIsRunning(this MauiActivityIndicator mauiActivityIndicator, IActivityIndicator activityIndicator) | ||
{ | ||
// TODO: Use IView Opacity if the ActivityIndicator is running. | ||
mauiActivityIndicator.ElementOpacity = activityIndicator.IsRunning ? 1 : 0; | ||
} | ||
public static void UpdateColor(this MauiActivityIndicator mauiActivityIndicator, IActivityIndicator activityIndicator) | ||
{ | ||
mauiActivityIndicator.UpdateColor(activityIndicator, null); | ||
} | ||
|
||
public static void UpdateColor(this MauiActivityIndicator mauiActivityIndicator, IActivityIndicator activityIndicator, object? foregroundDefault) | ||
{ | ||
Color color = activityIndicator.Color; | ||
|
||
if (color.IsDefault()) | ||
{ | ||
if (foregroundDefault != null) | ||
mauiActivityIndicator.RestoreForegroundCache(foregroundDefault); | ||
} | ||
else | ||
{ | ||
mauiActivityIndicator.Foreground = color.ToNative(); | ||
} | ||
} | ||
} | ||
} |
144 changes: 144 additions & 0 deletions
144
src/Core/src/Platform/Windows/FrameworkElementExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
#nullable enable | ||
using System; | ||
using System.Linq; | ||
using Microsoft.UI.Xaml; | ||
using System.Collections.Concurrent; | ||
using Microsoft.UI.Xaml.Media; | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using Microsoft.UI.Xaml.Controls; | ||
using WBinding = Microsoft.UI.Xaml.Data.Binding; | ||
using WBrush = Microsoft.UI.Xaml.Media.Brush; | ||
using WBindingExpression = Microsoft.UI.Xaml.Data.BindingExpression; | ||
|
||
namespace Microsoft.Maui | ||
{ | ||
internal static class FrameworkElementExtensions | ||
{ | ||
static readonly Lazy<ConcurrentDictionary<Type, DependencyProperty>> ForegroundProperties = | ||
new Lazy<ConcurrentDictionary<Type, DependencyProperty>>(() => new ConcurrentDictionary<Type, DependencyProperty>()); | ||
|
||
public static WBrush GetForeground(this FrameworkElement element) | ||
{ | ||
if (element == null) | ||
throw new ArgumentNullException(nameof(element)); | ||
|
||
return (WBrush)element.GetValue(GetForegroundProperty(element)); | ||
} | ||
|
||
public static WBinding? GetForegroundBinding(this FrameworkElement element) | ||
{ | ||
WBindingExpression expr = element.GetBindingExpression(GetForegroundProperty(element)); | ||
|
||
if (expr == null) | ||
return null; | ||
|
||
return expr.ParentBinding; | ||
} | ||
|
||
public static object GetForegroundCache(this FrameworkElement element) | ||
{ | ||
WBinding? binding = GetForegroundBinding(element); | ||
|
||
if (binding != null) | ||
return binding; | ||
|
||
return GetForeground(element); | ||
} | ||
|
||
public static void RestoreForegroundCache(this FrameworkElement element, object cache) | ||
{ | ||
var binding = cache as WBinding; | ||
if (binding != null) | ||
SetForeground(element, binding); | ||
else | ||
SetForeground(element, (WBrush)cache); | ||
} | ||
|
||
public static void SetForeground(this FrameworkElement element, WBrush foregroundBrush) | ||
{ | ||
if (element == null) | ||
throw new ArgumentNullException(nameof(element)); | ||
|
||
element.SetValue(GetForegroundProperty(element), foregroundBrush); | ||
} | ||
|
||
public static void SetForeground(this FrameworkElement element, WBinding binding) | ||
{ | ||
if (element == null) | ||
throw new ArgumentNullException(nameof(element)); | ||
|
||
element.SetBinding(GetForegroundProperty(element), binding); | ||
} | ||
|
||
internal static IEnumerable<T?> GetDescendantsByName<T>(this DependencyObject parent, string elementName) where T : DependencyObject | ||
{ | ||
int myChildrenCount = VisualTreeHelper.GetChildrenCount(parent); | ||
for (int i = 0; i < myChildrenCount; i++) | ||
{ | ||
var child = VisualTreeHelper.GetChild(parent, i); | ||
var controlName = child.GetValue(FrameworkElement.NameProperty) as string; | ||
if (controlName == elementName && child is T t) | ||
yield return t; | ||
else | ||
{ | ||
foreach (var subChild in child.GetDescendantsByName<T>(elementName)) | ||
yield return subChild; | ||
} | ||
} | ||
} | ||
|
||
internal static T? GetFirstDescendant<T>(this DependencyObject element) where T : FrameworkElement | ||
{ | ||
int count = VisualTreeHelper.GetChildrenCount(element); | ||
for (var i = 0; i < count; i++) | ||
{ | ||
DependencyObject child = VisualTreeHelper.GetChild(element, i); | ||
|
||
if ((child as T ?? GetFirstDescendant<T>(child)) is T target) | ||
return target; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
static DependencyProperty? GetForegroundProperty(FrameworkElement element) | ||
{ | ||
if (element is Control) | ||
return Control.ForegroundProperty; | ||
if (element is TextBlock) | ||
return TextBlock.ForegroundProperty; | ||
|
||
Type type = element.GetType(); | ||
|
||
if (!ForegroundProperties.Value.TryGetValue(type, out var foregroundProperty)) | ||
{ | ||
if (ReflectionExtensions.GetFields(type).FirstOrDefault(f => f.Name == "ForegroundProperty") is not FieldInfo field) | ||
throw new ArgumentException("type is not a Foregroundable type"); | ||
|
||
if (field.GetValue(null) is DependencyProperty property) | ||
ForegroundProperties.Value.TryAdd(type, property); | ||
|
||
return null; | ||
} | ||
|
||
return foregroundProperty; | ||
} | ||
|
||
internal static IEnumerable<T?> GetChildren<T>(this DependencyObject parent) where T : DependencyObject | ||
{ | ||
int myChildrenCount = VisualTreeHelper.GetChildrenCount(parent); | ||
for (int i = 0; i < myChildrenCount; i++) | ||
{ | ||
var child = VisualTreeHelper.GetChild(parent, i); | ||
if (child is T t) | ||
yield return t; | ||
else | ||
{ | ||
foreach (var subChild in child.GetChildren<T>()) | ||
yield return subChild; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using Microsoft.UI.Xaml; | ||
using Microsoft.UI.Xaml.Controls; | ||
|
||
namespace Microsoft.Maui | ||
{ | ||
public class MauiActivityIndicator : ProgressBar | ||
{ | ||
public static readonly DependencyProperty ElementOpacityProperty = DependencyProperty.Register( | ||
nameof(ElementOpacity), typeof(double), typeof(MauiActivityIndicator), new PropertyMetadata(default(double))); | ||
|
||
public double ElementOpacity | ||
{ | ||
get => (double)GetValue(ElementOpacityProperty); | ||
set => SetValue(ElementOpacityProperty, value); | ||
} | ||
|
||
protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize) | ||
{ | ||
var result = base.MeasureOverride(availableSize); | ||
|
||
if (!double.IsInfinity(availableSize.Width)) | ||
result.Width = availableSize.Width; | ||
|
||
return result; | ||
} | ||
} | ||
} |
Oops, something went wrong.