Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[XamlC] correctly resolve override of virtual event handlers (#247)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephaneDelcroix authored and Jason Smith committed Jul 18, 2016
1 parent e368168 commit d52f110
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 1 deletion.
14 changes: 13 additions & 1 deletion Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,12 @@ internal static string GetContentProperty(TypeReference typeRef)
//If the target is an event, connect
// IL_0007: ldloc.0
// IL_0008: ldarg.0
//
// IL_0009: ldftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
//OR, if the handler is virtual
// IL_000x: ldarg.0
// IL_0009: ldvirtftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
//
// IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
// IL_0014: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::add_Clicked(class [mscorlib]System.EventHandler)

Expand Down Expand Up @@ -345,7 +350,14 @@ internal static string GetContentProperty(TypeReference typeRef)
string.Format("EventHandler \"{0}\" not found in type \"{1}\"", value, context.Body.Method.DeclaringType.FullName),
iXmlLineInfo);
}
context.IL.Emit(OpCodes.Ldftn, handler);
if (handler.IsVirtual)
{
context.IL.Emit(OpCodes.Ldarg_0);
context.IL.Emit(OpCodes.Ldvirtftn, handler);
}
else
context.IL.Emit(OpCodes.Ldftn, handler);

//FIXME: eventually get the right ctor instead fo the First() one, just in case another one could exists (not even sure it's possible).
var ctor = module.Import(eventinfo.EventType.Resolve().GetConstructors().First());
ctor = ctor.ResolveGenericParameters(eventinfo.EventType, module);
Expand Down
2 changes: 2 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/EventsConnection.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
Clicked="HandleClickedOnBase" />
<local:ElementWithEvent x:Name="elementwithAsyncprivateHandler"
Clicked="HandleClickedPrivateAsync" />
<local:ElementWithEvent x:Name="elementWithVirtualHandler"
Clicked="HandleVirtualClicked" />
</StackLayout>
</local:BaseForEvents>
37 changes: 37 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/EventsConnection.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ async void HandleClickedPrivateAsync (object sender, EventArgs e)
asyncPrivateClicked++;
}

int baseForVirtualClicked;
protected virtual void HandleVirtualClicked(object sender, EventArgs e)
{
baseForVirtualClicked++;
}

[TestFixture]
public class Tests
{
Expand Down Expand Up @@ -113,6 +119,37 @@ public void TestAsyncPrivateHandler (bool useCompiledXaml)
layout.elementwithAsyncprivateHandler.SendClicked ();
Assert.AreEqual (1, layout.asyncPrivateClicked);
}

[TestCase(false)]
[TestCase(true)]
public void TestVirtualHandler(bool useCompiledXaml)
{
var layout = new SubForEvents(useCompiledXaml);
Assert.AreEqual(0, layout.baseForVirtualClicked);
Assert.AreEqual(0, layout.overrideClicked);
layout.elementWithVirtualHandler.SendClicked();
Assert.AreEqual(0, layout.baseForVirtualClicked);
Assert.AreEqual(1, layout.overrideClicked);
}
}
}

public class SubForEvents : EventsConnection
{
public SubForEvents(bool useCompiledXaml) : base(useCompiledXaml)
{
}

public int overrideClicked;
protected override void HandleVirtualClicked(object sender, EventArgs e)
{
overrideClicked++;
}

#pragma warning disable 1998 // considered for removal
async void HandleClickedPrivateAsync(object sender, EventArgs e)
#pragma warning restore 1998
{
}
}
}

0 comments on commit d52f110

Please sign in to comment.