Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev/xyguy/20231207/responsive-attached-property #957

Merged
merged 9 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions samples/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,25 @@
<PackageVersion Include="SkiaSharp.Views.Uno.WinUI" Version="2.88.6" />
<PackageVersion Include="Uno.Core.Extensions.Compatibility" Version="4.0.1" />
<PackageVersion Include="Uno.Core.Extensions.Logging.Singleton" Version="4.0.1" />
<PackageVersion Include="Uno.Cupertino" Version="4.1.0-dev.24" />
<PackageVersion Include="Uno.Cupertino.WinUI" Version="4.0.4" />
<PackageVersion Include="Uno.Extensions.Logging.OSLog" Version="1.4.0" />
<PackageVersion Include="Uno.Extensions.Logging.WebAssembly.Console" Version="1.4.0" />
<PackageVersion Include="Uno.Material" Version="4.1.0-dev.24" />
<PackageVersion Include="Uno.Material.WinUI" Version="4.1.0-dev.24" />
<PackageVersion Include="Uno.UI" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.UI.Adapter.Microsoft.Extensions.Logging" Version="4.5.9" />
<PackageVersion Include="Uno.UI.RemoteControl" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.UI.Skia.Gtk" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.UI.Skia.Wpf" Version="5.1.0-dev.156" />
<PackageVersion Include="Uno.UI.WebAssembly" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.Cupertino" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.Cupertino.WinUI" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.Extensions.Logging.OSLog" Version="1.8.0-dev.1" />
<PackageVersion Include="Uno.Extensions.Logging.WebAssembly.Console" Version="1.8.0-dev.1" />
<PackageVersion Include="Uno.Material" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.Material.WinUI" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.UI" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.UI.Adapter.Microsoft.Extensions.Logging" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.UI.RemoteControl" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.UI.Skia.Gtk" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.UI.Skia.Wpf" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.UI.WebAssembly" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.UniversalImageLoader" Version="1.9.36" />
<PackageVersion Include="Uno.Wasm.Bootstrap" Version="7.0.20" />
<PackageVersion Include="Uno.Wasm.Bootstrap.DevServer" Version="7.0.20" />
<PackageVersion Include="Uno.WinUI" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.WinUI.RemoteControl" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.WinUI.Skia.Gtk" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.WinUI.WebAssembly" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.Wasm.Bootstrap" Version="8.0.0-dev.306" />
<PackageVersion Include="Uno.Wasm.Bootstrap.DevServer" Version="8.0.0-dev.306" />
<PackageVersion Include="Uno.WinUI" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.WinUI.RemoteControl" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.WinUI.Skia.Gtk" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.WinUI.WebAssembly" Version="5.1.0-dev.975" />
<PackageVersion Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.3" />
<!-- Required to avoid warnings in 1.9.0.1 of Android.Material - https://github.com/xamarin/AndroidX/issues/727 -->
<PackageVersion Include="Xamarin.AndroidX.Annotation" Version="1.6.0.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,45 @@
<DataTemplate>
<StackPanel Spacing="20">

<!-- string literal -->
<TextBlock Text="Text test" FontWeight="Bold" />
<TextBlock Text="{utu:Responsive Narrow='Narrow Threshold 300', Normal='Normal Threshold 600', Wide='Wide Threshold 800'}" />

<!-- primitive literal -->
<TextBlock Text="FontSize test" FontWeight="Bold" />
<TextBlock Text="Normal 15 Wide 25" FontSize="{utu:Responsive Normal=15, Wide=25}" />

<!-- enum literal -->
<TextBlock Text="Orientation test | Normal=Vertical | Wide=Horizontal" FontWeight="Bold" />
<StackPanel Orientation="{utu:Responsive Normal=Vertical, Wide=Horizontal}">
<TextBlock Text="A" />
<TextBlock Text="B" />
<TextBlock Text="C" />
</StackPanel>

<TextBlock Text="Text test" FontWeight="Bold" />
<TextBlock Text="{utu:Responsive Narrow='Narrow Threshold 300', Normal='Normal Threshold 600', Wide='Wide Threshold 800'}" />

<TextBlock Text="FontSize test" FontWeight="Bold" />
<TextBlock Text="Normal 15 Wide 25" FontSize="{utu:Responsive Normal=15, Wide=25}" />

<!-- xaml parsable object -->
<TextBlock Text="Color test | Normal Red | Wide Blue" FontWeight="Bold" />
<Border Width="30"
Height="30"
HorizontalAlignment="Left"
Background="{utu:Responsive Normal=Red,
Wide=Blue}" />

<!-- attached property -->
<TextBlock Text="Grid.Column test: Narrowest=0, 1, 0, 1, Widest=0" FontWeight="Bold" />
<Grid Width="100"
Height="50"
Background="SkyBlue"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Border Grid.Column="{utu:Responsive Narrowest=0, Narrow=1, Normal=0, Wide=1, Widest=0}" Background="Pink" />
</Grid>

<!-- layout overriding -->
<TextBlock Text="Custom values override" FontWeight="Bold" />
<StackPanel>
<TextBlock Text="Global Override:" />
Expand Down
20 changes: 10 additions & 10 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@
<PackageVersion Include="Uno.Core.Extensions.Collections" Version="4.0.1" />
<PackageVersion Include="Uno.Core.Extensions.Logging.Singleton" Version="4.0.1" />
<PackageVersion Include="Uno.Core.Extensions.Logging" Version="4.0.1" />
<PackageVersion Include="Uno.Cupertino" Version="4.1.0-dev.24" />
<PackageVersion Include="Uno.Cupertino.WinUI" Version="4.1.0-dev.24" />
<PackageVersion Include="Uno.Extensions.Markup.Generators" Version="5.0.13" />
<PackageVersion Include="Uno.Cupertino" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.Cupertino.WinUI" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.Extensions.Markup.Generators" Version="5.1.0-dev.78" />
<PackageVersion Include="Uno.SourceGenerationTasks" Version="4.2.0" />
<PackageVersion Include="Uno.WinUI.Markup" Version="5.1.0-dev.54" />
<PackageVersion Include="Uno.Material" Version="4.1.0-dev.24" />
<PackageVersion Include="Uno.Material.WinUI" Version="4.1.0-dev.24" />
<PackageVersion Include="Uno.UI" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.WinUI" Version="5.1.0-dev.486" />
<PackageVersion Include="Uno.XamlMerge.Task" Version="1.1.0-dev.12" />
<PackageVersion Include="Uno.WinUI.Markup" Version="5.1.0-dev.78" />
<PackageVersion Include="Uno.Material" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.Material.WinUI" Version="4.1.0-dev.39" />
<PackageVersion Include="Uno.UI" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.WinUI" Version="5.1.0-dev.975" />
<PackageVersion Include="Uno.XamlMerge.Task" Version="1.32.0-dev.61" />
<PackageVersion Include="FluentAssertions" Version="5.10.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageVersion Include="NunitXml.TestLogger" Version="3.0.131" />
<PackageVersion Include="Uno.UI.RuntimeTests.Engine" Version="0.14.0-dev.54" />
<PackageVersion Include="Uno.UI.RuntimeTests.Engine" Version="0.25.0-dev.99" />
<PackageVersion Include="Uno.UITest" Version="1.1.0-dev.70" />
<PackageVersion Include="Uno.UITest.Helpers" Version="1.1.0-dev.70" />
<PackageVersion Include="Uno.UITest.Selenium" Version="1.1.0-dev.70" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Uno.Toolkit.UI;
using Uno.UI.RuntimeTests;

#if IS_WINUI
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
#endif

namespace Uno.Toolkit.RuntimeTests.Tests;

[TestClass]
[RunsOnUIThread]
internal class DependencyObjectExtensionTests
{
[TestMethod]
public void When_Type_FindDependencyProperty()
{
var dp = typeof(Grid).FindDependencyProperty<Thickness>(nameof(Grid.PaddingProperty));

Assert.AreEqual(Grid.PaddingProperty, dp);
}

[TestMethod]
public void When_Type_FindDependencyProperty_Attached()
{
var dp = typeof(Grid).FindDependencyProperty<int>(nameof(Grid.RowProperty));

Assert.AreEqual(Grid.RowProperty, dp);
}

[TestMethod]
public void When_DO_FindDependencyProperty()
{
var dp = new Grid().FindDependencyProperty<Thickness>(nameof(Grid.PaddingProperty));

Assert.AreEqual(Grid.PaddingProperty, dp);
}

[TestMethod]
public void When_DO_FindDependencyProperty_Attached()
{
var dp = new Grid().FindDependencyProperty<int>(nameof(Grid.RowProperty));

Assert.AreEqual(Grid.RowProperty, dp);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ private void InvalidateShadows(bool force = false)
StackPanel => StackPanel.CornerRadiusProperty,

Shape => null, // note: shapes have special handling, see: GetShadowShapeContext
DependencyObject @do => @do.FindDependencyPropertyUsingReflection<CornerRadius>("CornerRadiusProperty"),
DependencyObject @do => @do.FindDependencyProperty<CornerRadius>("CornerRadiusProperty"),
_ => null,
};
}
Expand All @@ -392,7 +392,7 @@ private void InvalidateShadows(bool force = false)
StackPanel stackpanel => stackpanel.CornerRadius,

Shape => null, // note: shapes have special handling, see: GetShadowShapeContext
DependencyObject @do => @do.FindDependencyPropertyUsingReflection<CornerRadius>("CornerRadiusProperty") is { } dp
DependencyObject @do => @do.FindDependencyProperty<CornerRadius>("CornerRadiusProperty") is { } dp
? (CornerRadius)@do.GetValue(dp)
: null,
_ => null,
Expand Down
62 changes: 26 additions & 36 deletions src/Uno.Toolkit.UI/Extensions/DependencyObjectExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Uno.Disposables;
using Uno.Extensions;
using System.Reflection;
using Microsoft.Extensions.Logging;
using Uno.Logging;

Expand All @@ -25,7 +25,7 @@ namespace Uno.Toolkit.UI
{
internal static class DependencyObjectExtensions
{
private static Dictionary<(Type type, string property), DependencyProperty?> _dependencyPropertyReflectionCache = new Dictionary<(Type, string), DependencyProperty?>(2);
private static Dictionary<(Type Type, string Property), DependencyProperty?> _dependencyPropertyReflectionCache = new Dictionary<(Type, string), DependencyProperty?>(2);

#if HAS_UNO
/// <summary>
Expand Down Expand Up @@ -182,65 +182,55 @@ internal static void SetParent(this DependencyObject dependencyObject, object? p
}
#endif

public static DependencyProperty? FindDependencyPropertyUsingReflection<TProperty>(this DependencyObject dependencyObject, string propertyName)
{
var type = dependencyObject.GetType();
var propertyType = typeof(TProperty);
var key = (ownerType: type, propertyName);
public static DependencyProperty? FindDependencyProperty<TProperty>(this DependencyObject owner, string propertyName) => owner.GetType().FindDependencyProperty<TProperty>(propertyName);

if (_dependencyPropertyReflectionCache.TryGetValue(key, out var property))
{
return property;
}
public static DependencyProperty? FindDependencyProperty(this DependencyObject owner, string propertyName) => owner.GetType().FindDependencyProperty(propertyName);

property =
type.GetProperty(propertyName, Public | Static | FlattenHierarchy)?.GetValue(null) as DependencyProperty ??
type.GetField(propertyName, Public | Static | FlattenHierarchy)?.GetValue(null) as DependencyProperty;
public static DependencyProperty? FindDependencyProperty<TProperty>(this Type ownerOrDescendantType, string propertyName)
{
var propertyType = typeof(TProperty);
var property = FindDependencyProperty(ownerOrDescendantType, propertyName);

#if HAS_UNO
if (property == null)
{
typeof(DependencyObjectExtensions).Log().LogWarning($"The '{type}.{propertyName}' dependency property does not exist.");
}
else if (property.GetType() != propertyType)
// note: for winui, it is no possible to obtain the property type from DependencyProperty by reflection.
// we can only check the sibling {propertyName} property or G/Set{propertyName} method (for attached dp) for the property type.
if (property != null && (
property.GetType().GetProperty("Type", NonPublic | Instance)?.GetValue(property) is not Type type ||
type != propertyType
))
{
typeof(DependencyObjectExtensions).Log().LogWarning($"The '{type}.{propertyName}' dependency property is not of the expected '{propertyType}' type.");
typeof(DependencyObjectExtensions).Log().LogWarning($"The '{ownerOrDescendantType.GetType().Name}.{propertyName}' dependency property is not of the expected '{propertyType.Name}' type.");
property = null;
}
#endif

_dependencyPropertyReflectionCache[key] = property;

return property;
}

public static DependencyProperty? FindDependencyPropertyUsingReflection(this DependencyObject dependencyObject, string propertyName)
public static DependencyProperty? FindDependencyProperty(this Type ownerOrDescendantType, string propertyName)
{
var type = dependencyObject.GetType();
var type = ownerOrDescendantType;
var key = (ownerType: type, propertyName);

if (_dependencyPropertyReflectionCache.TryGetValue(key, out var property))
// given that we are doing FlattenHierarchy lookup, it is fine that we are storing multiple pairs of (types-to-same-dp)
// since it is not worth the trouble to handle the type hierarchy...
if (!_dependencyPropertyReflectionCache.TryGetValue(key, out var property))
{
return property;
property =
type.GetProperty(propertyName, Public | Static | FlattenHierarchy)?.GetValue(null) as DependencyProperty ??
type.GetField(propertyName, Public | Static | FlattenHierarchy)?.GetValue(null) as DependencyProperty;
_dependencyPropertyReflectionCache[key] = property;
}

property =
type.GetProperty(propertyName, Public | Static | FlattenHierarchy)?.GetValue(null) as DependencyProperty ??
type.GetField(propertyName, Public | Static | FlattenHierarchy)?.GetValue(null) as DependencyProperty;

#if HAS_UNO
if (property == null)
{
typeof(DependencyObjectExtensions).Log().LogWarning($"The '{type}.{propertyName}' dependency property does not exist.");
typeof(DependencyObjectExtensions).Log().LogWarning($"The dependency property '{propertyName}' does not exist on '{type}' or its ancestors.");
}
#endif

_dependencyPropertyReflectionCache[key] = property;

return property;
}

public static bool TryGetValue(this DependencyObject dependencyObject, DependencyProperty dependencyProperty, out DependencyObject? value)
private static bool TryGetValue(this DependencyObject dependencyObject, DependencyProperty dependencyProperty, out DependencyObject? value)
{
value = default;

Expand Down
6 changes: 3 additions & 3 deletions src/Uno.Toolkit.UI/Helpers/PaddingHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static Thickness GetPadding(UIElement uiElement)
return padding;
}

var property = uiElement.FindDependencyPropertyUsingReflection<Thickness>("PaddingProperty");
var property = uiElement.FindDependencyProperty<Thickness>("PaddingProperty");
return property != null && uiElement.GetValue(property) is Thickness t ? t : default;
}

Expand All @@ -35,7 +35,7 @@ public static bool SetPadding(UIElement uiElement, Thickness padding)
return true;
}

var property = uiElement.FindDependencyPropertyUsingReflection<Thickness>("PaddingProperty");
var property = uiElement.FindDependencyProperty<Thickness>("PaddingProperty");
if (property != null)
{
uiElement.SetValue(property, padding);
Expand All @@ -53,7 +53,7 @@ public static bool TryUpdatePadding(this FrameworkElement frameworkElement, Thic
return !padding.Equals(newPadding) && TrySetPadding(frameworkElement, newPadding);
}

var property = frameworkElement.FindDependencyPropertyUsingReflection<Thickness>("PaddingProperty");
var property = frameworkElement.FindDependencyProperty<Thickness>("PaddingProperty");
if (property is { } && frameworkElement.GetValue(property) is Thickness currentPadding)
{
if (!currentPadding.Equals(newPadding))
Expand Down
18 changes: 5 additions & 13 deletions src/Uno.Toolkit.UI/Markup/ResponsiveExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using Windows.Foundation;
using Uno.Extensions;
using Uno.Logging;
using System.Diagnostics.CodeAnalysis;
using System.Linq;



#if IS_WINUI
using Microsoft.UI.Xaml;
Expand Down Expand Up @@ -85,21 +82,16 @@ private void BindToEvents(IXamlServiceProvider serviceProvider)
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget pvt &&
pvt.TargetObject is FrameworkElement target &&
pvt.TargetProperty is ProvideValueTargetProperty pvtp &&
target.FindDependencyPropertyUsingReflection($"{pvtp.Name}Property") is DependencyProperty dp)
pvtp.DeclaringType.FindDependencyProperty($"{pvtp.Name}Property") is DependencyProperty dp)
{
TargetWeakRef = new WeakReference(target);
_targetProperty = dp;
_propertyType =
#if HAS_UNO // workaround for uno#14719: uno doesn't inject the proper pvtp.Type
typeof(DependencyProperty).GetProperty("Type", Instance | NonPublic)?.GetValue(dp) as Type;
#else
pvtp.Type;
#endif
_propertyType = pvtp.Type;

// here, we need to bind to two events:
// 1. Window.SizeChanged for obvious reason
// 2. Control.Loaded because the initial value(result of ProvideValue) is resolved without the inherited .resources
// which may define a different DefaultResponsiveLayout resource somewhere along the visual tree, so we need to rectify that.

ResponsiveHelper.GetForCurrentView().Register(this);
target.Loaded += OnTargetLoaded;

Expand Down Expand Up @@ -158,7 +150,7 @@ private void UpdateBindingIfNeeded(ResponsiveHelper? helper = null, bool forceAp
var helper = ResponsiveHelper.GetForCurrentView();
var resolved = helper.ResolveLayout(GetAppliedLayout(), GetAvailableLayoutOptions());
var value = GetValueFor(resolved.Result);

CurrentValue = value;
CurrentLayout = resolved.Result;
LastResolved = resolved;
Expand Down
Loading
Loading