Skip to content

Commit

Permalink
fix(statetriggers): evaluate StateTriggers before the first layout cycle
Browse files Browse the repository at this point in the history
  • Loading branch information
ramezgerges committed Feb 19, 2025
1 parent d5e68d1 commit eb684d5
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 8 deletions.
42 changes: 42 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/Control/Control.crossruntime.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Linq;
using Uno.Extensions;
using Uno.UI.Xaml;

namespace Microsoft.UI.Xaml.Controls;

Expand All @@ -25,4 +27,44 @@ internal IFrameworkElement GetTemplateRoot()
{
return this.GetChildren()?.FirstOrDefault() as IFrameworkElement;
}

internal override void EnterImpl(EnterParams @params, int depth)
{
base.EnterImpl(@params, depth);

if (@params.IsLive)
{
// if (SupportsBuiltInStyles() && !m_fIsBuiltInStyleApplied)
// {
// // When we apply the built-in style, we may resolve theme resources in doing so
// // that haven't yet been resolved - for example, if a property value references
// // a resource that then references another resource.
// // We need to make sure we're operating under the correct theme during that resolution.
// bool removeRequestedTheme = false;
// const auto theme = GetTheme();
// const auto oldRequestedThemeForSubTree = GetRequestedThemeForSubTreeFromCore();
//
// if (theme != Theming::Theme::None && Theming::GetBaseValue(theme) != oldRequestedThemeForSubTree)
// {
// SetRequestedThemeForSubTreeOnCore(theme);
// removeRequestedTheme = true;
// }
//
// auto themeGuard = wil::scope_exit([&] {
// if (removeRequestedTheme)
// {
// SetRequestedThemeForSubTreeOnCore(oldRequestedThemeForSubTree);
// }
// });
//
// IFC_RETURN(ApplyBuiltInStyle());
// }

// Initialize StateTriggers at this time. We need to wait for this to enter a visual tree
// since we need for it to be part of the main visual tree to know which visual tree's
// qualifier context to use. We also need to force an update because our visual tree root
// may have changed since the last enter.
VisualStateManager.InitializeStateTriggers(this, true /* forceUpdate */);
}
}
}
16 changes: 9 additions & 7 deletions src/Uno.UI/UI/Xaml/FrameworkElement.Layout.crossruntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,15 @@ internal void InvokeApplyTemplate(out bool addedVisuals)
{
ApplyTemplate(out addedVisuals);

//if (auto visualTree = VisualTree::GetForElementNoRef(pControl))
// {
// // Create VisualState StateTriggers and perform evaulation to determine initial state,
// // if we're in the visual tree (since we need it to get our qualifier context).
// // If we're not in the visual tree, we'll do this when we enter it.
// IFC(CVisualStateManager2::InitializeStateTriggers(this));
//}
var pControl = this as Control;

if (VisualTree.GetForElement(pControl) is { } visualTree)
{
// Create VisualState StateTriggers and perform evaulation to determine initial state,
// if we're in the visual tree (since we need it to get our qualifier context).
// If we're not in the visual tree, we'll do this when we enter it.
VisualStateManager.InitializeStateTriggers(pControl);
}

//var control = this as Control;

Expand Down
6 changes: 5 additions & 1 deletion src/Uno.UI/UI/Xaml/VisualStateGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,15 @@ private void OnParentChanged(object instance, object key, DependencyObjectParent
if (this.GetParent() is IFrameworkElement fe)
{
OnOwnerElementChanged();
#if !__CROSSRUNTIME__
fe.Loaded += OnOwnerElementLoaded;
#endif
fe.Unloaded += OnOwnerElementUnloaded;
_parentLoadedDisposable.Disposable = Disposable.Create(() =>
{
#if !__CROSSRUNTIME__
fe.Loaded -= OnOwnerElementLoaded;
#endif
fe.Unloaded -= OnOwnerElementUnloaded;
});
}
Expand All @@ -171,7 +175,7 @@ private void OnOwnerElementChanged()
ExecuteOnTriggers(t => t.OnOwnerElementChanged());
}

private void OnOwnerElementLoaded(object sender, RoutedEventArgs args)
internal void OnOwnerElementLoaded(object sender, RoutedEventArgs args)
{
if (_pendingOnOwnerElementChanged)
{
Expand Down
69 changes: 69 additions & 0 deletions src/Uno.UI/UI/Xaml/VisualStateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,5 +290,74 @@ private static (VisualStateGroup, VisualState) GetValidGroupAndState(string stat

return (null, null);
}

internal static void InitializeStateTriggers(DependencyObject pDO, bool forceUpdate = false)
{
if (pDO is not Control pControl)
{
return;
}

var groupCollection = VisualStateManager.GetVisualStateGroups(pControl);
if (groupCollection is null)
{
return;
}

// auto& groupCollectionMap = groupCollection->GetStateTriggerVariantMaps();
// if (forceUpdate)
// {
// // Forcing an update, clear the map
// groupCollectionMap.clear();
//
// // If we're forcing an update, we should also clear the state trigger variant maps in each group.
// for (auto group : *groupCollection)
// {
// static_cast<CVisualStateGroup*>(group)->m_pStateTriggerVariantMap = nullptr;
// }
//
// for (auto& groupContext : groupCollection->GetGroupContext())
// {
// groupContext.GetStateTriggerVariantMap() = nullptr;
// }
// }
//
// if (!groupCollectionMap.empty())
// {
// // If the map isn't clear, then we are already initialized or we weren't forced by diagnostics to update.
// // Adding triggers isn't something usually supported at runtime.
// return S_OK;
// }
//
// auto dataSource = CreateVisualStateManagerDataSource(groupCollection);
// auto dataSourceMap = dataSource->GetStateTriggerVariantMaps();
//
// if (!dataSourceMap.empty())
// {
// if (forceUpdate)
// {
// // Forcing an update, clear the map
// dataSourceMap.clear();
// }
//
// if (!dataSourceMap.empty())
// {
// // If the map isn't clear, then we are already initialized or we weren't forced by diagnostics to update.
// // Adding triggers isn't something usually supported at runtime.
// return S_OK;
// }
// }
//
// VisualStateManagerActuator actuator(
// static_cast<CFrameworkElement*>(pControl->GetFirstChildNoAddRef()), dataSource.get());
// IFC_RETURN(actuator.InitializeStateTriggers(pControl));

// Uno Specific
foreach (var visualStateGroup in GetVisualStateGroups(pControl))
{
visualStateGroup.OnOwnerElementLoaded(pControl, null);
visualStateGroup.RefreshStateTriggers(forceUpdate);
}
}
}
}

0 comments on commit eb684d5

Please sign in to comment.