diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs index 61a352e5f373..0150fe649412 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs @@ -353,6 +353,7 @@ private SourceText InnerGenerateFile() if (topLevelControl.Type.Name == "ResourceDictionary") { _isTopLevelDictionary = true; + _xClassName = FindClassName(topLevelControl); using (TrySetDefaultBindMode(topLevelControl)) { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentControl.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentControl.cs index b4cec795b704..76e568289c29 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentControl.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ContentControl.cs @@ -187,6 +187,43 @@ public async Task When_Content_Set_Null_ComboBox() Assert.IsTrue(comboBox.SelectedIndex == -1); } +#if HAS_UNO + [TestMethod] + [RunsOnUIThread] + public async Task When_FindName_ContentControl_Without_ContentTemplate() + { + var sut = new ContentControl + { + Width = 100, + Height = 100, + Content = new TextBox() + }; + + WindowHelper.WindowContent = sut; + await WindowHelper.WaitForLoaded(sut); + + Assert.IsNotNull(sut.FindName("ContentElement")); + } + + [TestMethod] + [RunsOnUIThread] + public async Task When_FindName_ContentControl_With_ContentTemplate() + { + var sut = new ContentControl + { + Width = 100, + Height = 100, + Content = new TextBox(), + ContentTemplate = new DataTemplate(() => new TextBlock()) + }; + + WindowHelper.WindowContent = sut; + await WindowHelper.WaitForLoaded(sut); + + Assert.IsNull(sut.FindName("ContentElement")); + } +#endif + private class SignInViewModel { public string UserName { get; set; } = "Steve"; diff --git a/src/Uno.UI.Tests/App/App.xaml b/src/Uno.UI.Tests/App/App.xaml index d461fb3ee965..508d4071508f 100644 --- a/src/Uno.UI.Tests/App/App.xaml +++ b/src/Uno.UI.Tests/App/App.xaml @@ -6,6 +6,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:views="using:Uno.UI.Tests.App.Views" xmlns:local="using:Uno.UI.Tests.App.Xaml" + xmlns:xbind="using:Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls" mc:Ignorable="not_win"> @@ -31,6 +32,7 @@ + diff --git a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary.xaml b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary.xaml new file mode 100644 index 000000000000..a7d72305be0f --- /dev/null +++ b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary.xaml @@ -0,0 +1,30 @@ + + + + + diff --git a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary.xaml.cs b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary.xaml.cs new file mode 100644 index 000000000000..ee2c63b548a0 --- /dev/null +++ b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary.xaml.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +namespace Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls; +public sealed partial class XBind_ResourceDictionary : ResourceDictionary +{ + public XBind_ResourceDictionary() + { + this.InitializeComponent(); + } +} diff --git a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary_Control.cs b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary_Control.cs new file mode 100644 index 000000000000..b2fcede39860 --- /dev/null +++ b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Controls/XBind_ResourceDictionary_Control.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls; + +internal class XBind_ResourceDictionary_Control : Control +{ + /// + /// Creates a new instance of the class. + /// + public XBind_ResourceDictionary_Control() + { + this.DefaultStyleKey = typeof(XBind_ResourceDictionary_Control); + + // Allows directly using this control as the x:DataType in the template. + this.DataContext = this; + } + + public bool ElementLoadedInvoked { get; private set; } + + public void Element_Loaded(object sender, RoutedEventArgs args) + { + ElementLoadedInvoked = true; + } +} diff --git a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Given_xBind_Binding.cs b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Given_xBind_Binding.cs index 64deb0ecd5ae..a8076ac1fcdb 100644 --- a/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Given_xBind_Binding.cs +++ b/src/Uno.UI.Tests/Windows_UI_Xaml_Data/xBindTests/Given_xBind_Binding.cs @@ -1461,6 +1461,15 @@ public void When_Indexer_Then_Property_Access_Update_Collection_Element() Assert.AreEqual("Updated2", SUT.tbDict2.Text); } + [TestMethod] + public void When_XBind_In_ResourceDictionary() + { + var SUT = new XBind_ResourceDictionary_Control(); + SUT.ForceLoaded(); + + Assert.IsTrue(SUT.ElementLoadedInvoked); + } + private async Task AssertIsNullAsync(Func getter, TimeSpan? timeout = null) where T : class { timeout ??= TimeSpan.FromSeconds(1); diff --git a/src/Uno.UI/UI/Xaml/IFrameworkElement.cs b/src/Uno.UI/UI/Xaml/IFrameworkElement.cs index 6e24c5b809b2..8279264d4462 100644 --- a/src/Uno.UI/UI/Xaml/IFrameworkElement.cs +++ b/src/Uno.UI/UI/Xaml/IFrameworkElement.cs @@ -255,9 +255,17 @@ public static IFrameworkElement FindName(IFrameworkElement e, ViewGroup group, s // If element is a ContentControl with a view as Content, include the view and its children in the search, // to better match Windows behaviour - var content = - (e as ContentControl)?.Content as IFrameworkElement ?? - (e as Controls.Primitives.Popup)?.Child as IFrameworkElement; + IFrameworkElement content = null; + if (e is ContentControl contentControl && + contentControl.Content is IFrameworkElement innerContent && + contentControl.ContentTemplate is null) // Only include the Content view if there is no ContentTemplate. + { + content = innerContent; + } + else if (e is Controls.Primitives.Popup popup) + { + content = popup.Child as IFrameworkElement; + } if (content != null) {