[Android, iOS] Control templates are applied too early
I'm submitting a...
- Bug report (I searched for similar issues and did not find one)
Current behavior
If we instantiate a control and set the Template property, then this template is applied immediately (which leads to invoke the OnApplyTemplate in the control).
Expected behavior
On Windows the template of a control is being applied only when this control is in the visual tree and either we explicitly invoke the ApplyTemplate method, or we wait for the first measure pass.
Note: To get the full behavior of windows, we should be able to do:
var myControl = new MyControl { Template = _myControlTemplate };
_panelInTheVisualTree.Children.Add(myControl); // Template was not applied yet
myControl.ApplyTemplate(); // Will invoke `OnApplyTemplate` synchronously and returns `true`
_panelInTheVisualTree.Children.Remove(myControl); // `myControl` was not measured
But if the panel is not in the visual tree, myControl.ApplyTemplate() should not do anything and returns false
Minimal reproduction of the problem with instructions
var myControl = new MyControl { Template = _myControlTemplate };
Environment
Nuget Package: Uno.UI
Package Version(s): 1.25.0-dev.42
Affected platform(s):
- [x] iOS
- [x] Android
- [?] WebAssembly
- [ ] Windows
- [ ] Build tasks
Visual Studio : _Irrelevant_
Relevant plugins: _Irrelevant_
This got mitigated by #192, but it's still not properly aligned with UWP.
ApplyTemplate() doesn't require the view to be in the visual tree, it just requires Template to be non-null. If the Control has an implicit style then its Template will be null on UWP until it's in the visual tree because the Style can't be resolved until that point. The root cause then is #119.
For now the best workaround is to set FeatureConfiguration.Control.UseLegacyLazyApplyTemplate = true.
The specific issue we're encountering involves a custom control that wraps a ListView and accepts a DataTemplateSelector as a wrapper but includes a default DataTemplateSelector. By the time we have received the DataTemplateSelector the ListView has already been rendered using the default DataTemplateSelector.
This is causing some troubles again with this:
<Setter Property="DisplayTemplate" Value="{StaticResource templTextDisplay}" />
<Setter Property="InputTemplate" Value="{StaticResource templTextInput}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Fill="Red" Stretch="Fill" />
</ControlTemplate>
</Setter.Value>
</Setter>
If in the callback of the DisplayTemplateProperty you do something like Template = DisplayTemplate, then the OnApplyTemplate will be invoked twice (once with the DisplayTemplate and a second time withe the template defined in the style for the Template property).
On Windows the template is applied only on first measure, so the OnApplyTemplate is invoked only once (with the DisplayTemplate, but this is certainly due to https://github.com/unoplatform/uno/issues/3398)
This was causing an issue in one of the tests that I worked around in #14368.
For my case though, the issue is that control templates are not applied on the first measure pass, not that they are applied early.
I added some code comments in #14368 that mentions some of the relevant parts of WinUI source code.
This will be easily fixable after https://github.com/unoplatform/uno/pull/18261/ is merged
This is only relevant to native renderer, closing. CC @Jen-Uno
@MartinZikmund I'm curious. Are native renderers removed completely? Or they are there but are no longer a supported scenario and exists only for backcompat?