Skip to content

Commit 083fce5

Browse files
committed
feat: Add support for x:Name hot reload
1 parent 1c1d352 commit 083fce5

File tree

5 files changed

+96
-6
lines changed

5 files changed

+96
-6
lines changed

src/Uno.UI.Tests/Windows_UI_Xaml_Markup/XamlReaderTests/Given_XamlReader.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,30 @@ public void When_ThemeResource_And_Setter_And_Theme_Changed()
10001000

10011001
}
10021002

1003+
[TestMethod]
1004+
public void When_xName_Reload()
1005+
{
1006+
var s = GetContent(nameof(When_xName_Reload));
1007+
var SUT = new When_xName_Reload();
1008+
Windows.UI.Xaml.Markup.XamlReader.LoadUsingComponent(s, SUT);
1009+
1010+
var Button1_field_private = SUT.FindName("Button1_field_private") as Button;
1011+
Assert.IsNotNull(Button1_field_private);
1012+
Assert.AreEqual(Button1_field_private, SUT.Button1_field_private_Getter);
1013+
1014+
var Button1_field_public = SUT.FindName("Button1_field_public") as Button;
1015+
Assert.IsNotNull(Button1_field_public);
1016+
Assert.AreEqual(Button1_field_public, SUT.Button1_field_public);
1017+
1018+
var Button2_property_private = SUT.FindName("Button2_property_private") as Button;
1019+
Assert.IsNotNull(Button2_property_private);
1020+
Assert.AreEqual(Button2_property_private, SUT.Button2_property_private_Getter);
1021+
1022+
var Button2_property_public = SUT.FindName("Button2_property_public") as Button;
1023+
Assert.IsNotNull(Button2_property_public);
1024+
Assert.AreEqual(Button2_property_public, SUT.Button2_property_public);
1025+
}
1026+
10031027
private string GetContent(string testName)
10041028
{
10051029
var assembly = this.GetType().Assembly;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using Windows.UI.Xaml;
3+
using Windows.UI.Xaml.Controls;
4+
5+
namespace Uno.UI.Tests.Windows_UI_Xaml_Markup.XamlReaderTests
6+
{
7+
public partial class When_xName_Reload : UserControl
8+
{
9+
#pragma warning disable 649
10+
private Button Button1_field_private;
11+
12+
public Button Button1_field_public;
13+
14+
private Button Button2_property_private { get; set; }
15+
16+
public Button Button2_property_public { get; set; }
17+
18+
19+
public Button Button2_property_private_Getter => Button2_property_private;
20+
public Button Button1_field_private_Getter => Button1_field_private;
21+
}
22+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<UserControl
2+
x:Class="Uno.UI.Tests.Windows_UI_Xaml_Markup.XamlReaderTests.When_xName_Reload"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
>
6+
<StackPanel >
7+
<Button x:Name="Button1_field_private" Content="Button 1" />
8+
<Button x:Name="Button2_property_private" Content="Button 2" />
9+
<Button x:Name="Button1_field_public" Content="Button 1" />
10+
<Button x:Name="Button2_property_public" Content="Button 2" />
11+
</StackPanel>
12+
</UserControl>

src/Uno.UI/UI/Xaml/Markup/Reader/XamlObjectBuilder.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,11 @@ private string RewriteAttachedPropertyPath(string? value)
248248
return value;
249249
}
250250

251-
private void ProcessNamedMember(XamlObjectDefinition control, object instance, XamlMemberDefinition member, object rootInstance)
251+
private void ProcessNamedMember(
252+
XamlObjectDefinition control,
253+
object instance,
254+
XamlMemberDefinition member,
255+
object rootInstance)
252256
{
253257
// Exclude attached properties, must be set in the extended apply section.
254258
// If there is no type attached, this can be a binding.
@@ -356,6 +360,22 @@ private void ProcessNamedMember(XamlObjectDefinition control, object instance, X
356360
{
357361
GetPropertySetter(nameInfo).Invoke(instance, new[] { member.Value });
358362
}
363+
364+
// Update x:Name generated fields, if any
365+
if (rootInstance != null && member.Value is string nameValue)
366+
{
367+
var allMembers = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
368+
var rootInstanceType = rootInstance.GetType();
369+
370+
if (TypeResolver.GetPropertyByName(rootInstanceType, nameValue, allMembers) is { } xNameProperty)
371+
{
372+
GetPropertySetter(xNameProperty).Invoke(rootInstance, new[] { instance });
373+
}
374+
else if (TypeResolver.GetFieldByName(rootInstanceType, nameValue, allMembers) is { } xNameField)
375+
{
376+
xNameField.SetValue(rootInstance, instance);
377+
}
378+
}
359379
}
360380
}
361381

src/Uno.UI/UI/Xaml/Markup/Reader/XamlTypeResolver.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,26 @@ public bool IsInitializedCollection(PropertyInfo property)
103103
return false;
104104
}
105105

106-
public PropertyInfo? GetPropertyByName(XamlType declaringType, string propertyName)
107-
=> GetPropertyByName(FindType(declaringType), propertyName);
106+
public PropertyInfo? GetPropertyByName(XamlType declaringType, string propertyName, BindingFlags? flags = null)
107+
=> GetPropertyByName(FindType(declaringType), propertyName, flags);
108108

109-
public PropertyInfo? FindContentProperty(Type? elementType)
109+
public FieldInfo? GetFieldByName(XamlType declaringType, string propertyName, BindingFlags? flags = null)
110+
=> GetFieldByName(FindType(declaringType), propertyName, flags);
111+
112+
public PropertyInfo? FindContentProperty(Type? elementType)
110113
=> _findContentProperty(elementType);
111114

112-
private static PropertyInfo? GetPropertyByName(Type? type, string propertyName)
113-
=> type?.GetProperties().FirstOrDefault(p => p.Name == propertyName);
115+
public PropertyInfo? GetPropertyByName(Type? type, string propertyName, BindingFlags? flags = null)
116+
=> (flags != null
117+
? type?.GetProperties(flags.Value)
118+
: type?.GetProperties()
119+
).FirstOrDefault(p => p.Name == propertyName);
120+
121+
public FieldInfo? GetFieldByName(Type? type, string propertyName, BindingFlags? flags = null)
122+
=> (flags != null
123+
? type?.GetFields(flags.Value)
124+
: type?.GetFields()
125+
).FirstOrDefault(p => p.Name == propertyName);
114126

115127
public EventInfo? GetEventByName(XamlType declaringType, string eventName)
116128
=> GetEventByName(FindType(declaringType), eventName);

0 commit comments

Comments
 (0)