`Xamarin.Forms.BorderElement.OnBorderColorPropertyChanged` throws `System.InvalidCastException`
brminnick opened this issue · 8 comments
Problem
When the BorderColor
changes (via a Binding
or a DynamicResource
), Xamarin.Forms.BorderElement.OnBorderColorPropertyChanged
throws an InvalidCastException
.
OnBorderColorPropertyChanged
attempts to cast the PancakeView
to an IBorderElement
and a InvalidCastException
is thrown because PancakeView
does not implement IBorderElement
.
Here's the link to the Xamarin.Forms source code that is throwing the InvalidCastException
: https://github.com/xamarin/Xamarin.Forms/blob/719fc7a604ff0cce8922d717c99bfb0fa17e35e0/Xamarin.Forms.Core/BorderElement.cs#L19
Suggestion
Having PancakeView
implement IBorderElement
resolve the InvalidCastException
.
public class PancakeView : ContentView, IBorderElement
Reproduction
Reproduction Steps
- Download/Clone the
PancakeView-Border-Repro
branch ofGitTrends
: https://github.com/brminnick/GitTrends/tree/PancakeView-Border-Repro - In Visual Studio, open
GitTrends.sln
- In Visual Studio, set the startup project to GitTrends.iOS
- In Visual Studio, set the build configuration to DEBUG
- Build/deploy GitTrends.iOS to an iOS simulator / device
- On the iOS device, wait for GitTrends to load
- On the GitTrends Welcome Page page, on the bottom-right, click
SKIP
- On the GitTrends Connect to GitHub page, on the bottom-right, click
TRY DEMO
- Confirm the app crashes
Video
Stack Trace
Here is the stack trace from the by the reproduction sample, linked above.
BorderElement.OnBorderColorPropertyChanged (Xamarin.Forms.BindableObject bindable, System.Object oldValue, System.Object newValue)
BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent)
BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes)
Element.OnSetDynamicResource (Xamarin.Forms.BindableProperty property, System.String key)
BindableObject.SetDynamicResource (Xamarin.Forms.BindableProperty property, System.String key, System.Boolean fromStyle)
Element.SetDynamicResource (Xamarin.Forms.BindableProperty property, System.String key)
ElementExtensions.DynamicResources[TElement] (TElement element, System.ValueTuple`2[Xamarin.Forms.BindableProperty,System.String][] resources)
GitTrends.BaseRepositoryDataTemplate+CardView+CardViewFrame+ContentGrid+AvatarImage..ctor (System.String& avatarUrl) <0x104da828c + 0x0019b> in <b8c6e33f85b24874aaee293c45607f59#5b4fab3a7ddfb8e11daefb7ac1e330ab>:0
GitTrends.BaseRepositoryDataTemplate+CardView+CardViewFrame+ContentGrid..ctor (System.Collections.Generic.IEnumerable`1[Xamarin.Forms.View]& parentDataTemplateChildren, GitTrends.Shared.Repository& repository) <0x104da75f0 + 0x007d3> in <b8c6e33f85b24874aaee293c45607f59#5b4fab3a7ddfb8e11daefb7ac1e330ab>:0
GitTrends.BaseRepositoryDataTemplate+CardView+CardViewFrame..ctor (System.Collections.Generic.IEnumerable`1[Xamarin.Forms.View]& parentDataTemplateChildren, GitTrends.Shared.Repository& repository) <0x104da74f4 + 0x000b3> in <b8c6e33f85b24874aaee293c45607f59#5b4fab3a7ddfb8e11daefb7ac1e330ab>:0
GitTrends.BaseRepositoryDataTemplate+CardView..ctor (System.Collections.Generic.IEnumerable`1[Xamarin.Forms.View]& parentDataTemplateChildren, GitTrends.Shared.Repository& repository) <0x104da7108 + 0x00353> in <b8c6e33f85b24874aaee293c45607f59#5b4fab3a7ddfb8e11daefb7ac1e330ab>:0
<.ctor>b__0 ()
ElementTemplate.CreateContent ()
TemplatedCell.Bind (Xamarin.Forms.DataTemplate template, System.Object bindingContext, Xamarin.Forms.ItemsView itemsView)
ItemsViewController`1[TItemsView].UpdateTemplatedCell (Xamarin.Forms.Platform.iOS.TemplatedCell cell, Foundation.NSIndexPath indexPath)
ItemsViewController`1[TItemsView].GetCell (UIKit.UICollectionView collectionView, Foundation.NSIndexPath indexPath)
ItemsViewController`1[TItemsView].GetPrototype ()
ItemsViewLayout.DetermineCellSize ()
ListViewLayout.ConstrainTo (CoreGraphics.CGSize size)
ItemsViewController`1[TItemsView].CheckForEmptySource ()
ItemsViewController`1[TItemsView].NumberOfSections (UIKit.UICollectionView collectionView)
(wrapper managed-to-native) ObjCRuntime.Messaging.objc_msgSendSuper(intptr,intptr)
UICollectionViewLayout.PrepareLayout ()
ItemsViewLayout.PrepareLayout ()
(wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr)
UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate)
UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName)
Application.Main (System.String[] args)
Thanks for the clear repro, I'll look into it.
I'm wondering though how/why XamForms suddenly decides that this is a BorderElement
. I'm not referencing that anywhere, so it has to have been changed somewhere along the inheritance chain from ContentView
upwards. Either way, I implemented the interface, but pretty much cleared out any implementation for it, as all of that is actually done through the Border
subclass. That way it won't get in the way of the current implementation. So I did this:
public Color BorderColor => default(Color);
int IBorderElement.CornerRadius => 0;
public double BorderWidth => 0;
public int CornerRadiusDefaultValue => 0;
public Color BorderColorDefaultValue => default(Color);
public double BorderWidthDefaultValue => 0;
public bool IsCornerRadiusSet() => false;
public bool IsBackgroundColorSet() => false;
public bool IsBorderColorSet() => false;
public bool IsBorderWidthSet() => false;
However, that creates new issues:
In GitTrends > Views > Repository > BaseRepositoryDataTemplate.cs:L68
Content = new ContentGrid(parentDataTemplateChildren, repository);
Could not set up parent class, due to: Parent class vtable failed to initialize, due to: VTable setup of type Xamarin.Forms.PancakeView.PancakeView failed at GitTrends.BaseRepositoryDataTemplate+CardView+CardViewFrame..ctor (System.Collections.Generic.IEnumerable`1[Xamarin.Forms.View]& parentDataTemplateChildren, GitTrends.Shared.Repository& repository) [0x00054] in /Users/sthewissen/Downloads/GitTrends-PancakeView-Border-Repro/GitTrends/Views/Repository/BaseRepositoryDataTemplate.cs:68
at GitTrends.BaseRepositoryDataTemplate+CardView..ctor (System.Collections.Generic.IEnumerable`1[Xamarin.Forms.View]& parentDataTemplateChildren, GitTrends.Shared.Repository& repository) [0x000af] in /Users/sthewissen/Downloads/GitTrends-PancakeView-Border-Repro/GitTrends/Views/Repository/BaseRepositoryDataTemplate.cs:51
at GitTrends.BaseRepositoryDataTemplate+<>c__DisplayClass7_0.<.ctor>b__0 () [0x00000] in /Users/sthewissen/Downloads/GitTrends-PancakeView-Border-Repro/GitTrends/Views/Repository/BaseRepositoryDataTemplate.cs:28
at Xamarin.Forms.ElementTemplate.CreateContent () [0x00026] in D:\a\1\s\Xamarin.Forms.Core\ElementTemplate.cs:82
at Xamarin.Forms.Platform.iOS.TemplatedCell.Bind (Xamarin.Forms.DataTemplate template, System.Object bindingContext, Xamarin.Forms.ItemsView itemsView) [0x00052] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\TemplatedCell.cs:91
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].UpdateTemplatedCell (Xamarin.Forms.Platform.iOS.TemplatedCell cell, Foundation.NSIndexPath indexPath) [0x00012] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:199
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].GetCell (UIKit.UICollectionView collectionView, Foundation.NSIndexPath indexPath) [0x00033] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:84
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].GetPrototype () [0x0005d] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:263
at Xamarin.Forms.Platform.iOS.ItemsViewLayout.DetermineCellSize () [0x0004e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewLayout.cs:201
at Xamarin.Forms.Platform.iOS.ListViewLayout.ConstrainTo (CoreGraphics.CGSize size) [0x0001e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ListViewLayout.cs:16
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].CheckForEmptySource () [0x00039] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:114
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].NumberOfSections (UIKit.UICollectionView collectionView) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:181
at (wrapper managed-to-native) ObjCRuntime.Messaging.void_objc_msgSendSuper(intptr,intptr)
at UIKit.UICollectionViewLayout.PrepareLayout () [0x00023] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.20.2.2/src/Xamarin.iOS/UIKit/UICollectionViewLayout.g.cs:576
at Xamarin.Forms.Platform.iOS.ItemsViewLayout.PrepareLayout () [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewLayout.cs:385
at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr)
at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.20.2.2/src/Xamarin.iOS/UIKit/UIApplication.cs:86
at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0000e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.20.2.2/src/Xamarin.iOS/UIKit/UIApplication.cs:65
at GitTrends.iOS.Application.Main (System.String[] args) [0x00000] in /Users/sthewissen/Downloads/GitTrends-PancakeView-Border-Repro/GitTrends.iOS/Main.cs:5
Fun! Investigation continues, but happy to hear thoughts 😅
@brminnick I downgraded the PancakeView version in that GitTrends branch to v2.1.0.714 and it seems to work (it doesn't throw an exception at least). Apparently along the way while opening the can of worms that is AndroidX something changed that is impacting this in v2.2.* as that was the biggest change in there. I've subsequently pulled all the v2.2.* stuff from NuGet as I'm getting other issues related to this as well (e.g. #134).
Regarding an actual solution, I'm not quite sure when I'll get around to it. Other things in life are taking up a lot of time and will be for the foreseeable future.
2.2 is again there. Does it mean this issue was resolved?
ahh ok. I just recognized that my private feed cached 2.2 versions when i had package source=all on Nuget manager, it was pulling from my private feed :)
@brminnick I assume this regressed now in v2.3.754-beta? As the addition of IBorderElement
is basically causing #141. I'm clueless with regards to the vtable nonsense its spouting and where that's coming from, to be honest. I'm also pretty limited in time already and expect that to not change any time soon (👶 incoming).
Congrats on the baby!!
Yup - I confirmed System.InvalidCastException
is happening in v2.3.754-beta
Thanks! So either we solve this strange IBorderElement
cast (which is happening for some reason that I don't quite grasp yet) or we solve the vtable issue when implementing IBorderElement
(which is possibly even vaguer). Why is it casting to IBorderElement
? I would assume that a check needs to happen there if whatever it's casting even implements it. If it's not implemented somewhere up the inheritance chain for PancakeView, should XamForms even be assuming it is?