This is the story of my first bugfix in .NET MAUI. As a software architect, I work with a group of great developers. Sometimes we run into issues with the frameworks that we depend on, such as .NET MAUI for our mobile applications. The trick is to not stop there. Aside from reporting them, we can try to fix those issues.
For one of our apps, we wanted to create buttons with 90-degree corners. So we set the CornerRadius to 0 in the XAML.
<Button
CornerRadius="0"
BackgroundColor="Purple"
TextColor="White"
Text="CornerRadius" />
For iOS this worked fine, the result for Android was surprising:
We have encountered a bug in .NET MAUI. Specifically in the control “Button”, for the platform Android.
In .NET MAUI there is a very nice pattern called the “Handler Architecture”.
The code you write in the XAML is a “VirtualView” with a MAUI Control, Button in this case
The Handler converts the “Button” to an Android “AppCompatButton”.
For many issues with controls, you can write workarounds by modifying or replacing the Handler behavior. That is possible because handlers define a mapping, between properties and the conversion to the native platform. You can configure this in your app startup.
In this case, the issue was with what happened with the CornerRadius property.
I decided not to write a workaround.
It was time to open the hood (or bonnet for the British 🙃).
To investigate, I cloned the .NET MAUI solution from https://github.com/dotnet/maui and followed the steps in the Development Guide to build and run it.
Using my knowledge of the handler pattern, I searched for CornerRadius in the Android Button Handler.
And sure enough, this check on CornerRadius is suspicious.
if (button.CornerRadius > 0)
mauiDrawable.SetCornerRadius(button.CornerRadius);
So I set a breakpoint on this check and ran the Sandbox project in the MAUI solution with the Button with CornerRadius of 0. And indeed, this code is skipped, CornerRadius is not set! Then I changed this check to >= and ran again, and suddenly I had 90-degree corners!
Also, I noticed that the default CornerRadius is 6, so when it skips setting the radius to 0 it will be a rounded corner.
The next step was to open a Pull Request. These are the steps:
I started to look for related issues and was able to connect three open issues about this problem to the PR.
The reviewers suggested that a Device Test should be added. I got the nice comment that I should let them know if they made tests too weird 😀, they would be open for a call to help. I didn’t need that but it was nice that I got the offer for more collaboration.
A device test is a unit test that runs on the actual platform, in this case, Android. There is a Test Runner App that can run the unit tests. It looks like this on my phone:
If I tap “Run All Tests”, the processor goes up and the battery goes down 😆
Writing a test in this codebase was tricky, especially finding examples and getting the output CornerRadius from the handler. I used a Theory to run two tests, for radius of 0 and radius of 5. (XUnit)
Arrange phase, I setup a button with a CornerRadius of 0.
Act phase, I let the handler code execute and get two values:
The ViewValue for CornerRadius, from the CrossPlatform View input
The PlatformViewValue for CornerRadius, from the Handler output.
In getting the PlatformViewValue I use reflection to get the private variable cornerRadius*,* which is used in OnDraw(). In the drawing of a Button the vector path of the border and its corners is calculated. It uses cornerRadius in the calculation.
Assert phase, I check that the output value of the handler is identical to what I expect.
After committing this test the reviewers approved. It got merged into the main branch and I got a nice thank you. I am now a hungry contributor looking forward to an opportunity to fix another bug.
We as a community can make open-source work. For .NET MAUI the future is bright, in my opinion, the improvements are big between major .NET versions. If we help iron out the remaining issues that we encounter, this framework will be a big success.
Here you can find the Pull Request mentioned in this article: