I have managed to get two PRs merged with Xamarin.Forms that squash two bugs for UWP when using Xamarin.Forms. In this post, I will give you a little insight in how the bugs could happen and how I managed to fix them.
MaxLines bug #
Label MaxLines should display 4 lines and then truncation, but it only shows one line. If I remove the
LineBreakMode="TailTruncation"then I get 4 lines.
So it was clear, that together with the LineBreakMode, something breaks in the MaxLines on UWP. I quickly jumped in the code and went over to the LabelRenderer.cs file.
Because you are reading this post, I am going to assume you already have a faint idea of how Forms works, but just to refresh your memory a little bit, I will explain the very basics.
Xamarin.Forms works because of these renderers. It allows you to declare abstract controls like a Button, Entry or a Label and the Forms libraries (with the renderers) will translate those abstract controls into their native equivalents for the platform that you are running on. You can see a schematic overview of how that works with an Entry underneath. As the developer of your app, you can hook into those renderers or write your own completely (which I wouldn’t recommend) and create so-called custom renderers.
Xamarin.Forms renderers schematic overview
When a bug happens to occur in Xamarin.Forms, it will most likely be in the renderer of that control, since that is where most of the logic happens to map all the right properties from the abstract to the native control.
The UWP LabelRenderer #
That was also true for this bug. I started looking at the LabelRenderer for UWP and quickly noticed this piece of code:
Since the bug only appeared when used with LineBreakMode there had to be something in here. If you look closely you see that when truncation is applied, also the wrapping of this TextBlock is set to NoWrap. I hear you thinking: hold on, a TextBlock?! Yes! The TextBlock is the UWP equivalent of the Forms Label. That means, we have to project everything from our Label to the TextBlock which happens in the renderer.
NoWrap means that the text in the Label (or TextBlock) does not cross over to the next line when the actual text is overflowing the size of the label. While this does make sense, it starts to get weird when you have set the MaxLines property. Then you explicitly specify that you want the label to have multiple lines. I then implemented some code that checks to see if the MaxLines property is set and if it is, we allow the text to wrap. And with that, the bug was resolved!
IsPassword bug #
The other bug has to do with the IsPassword property on an Entry. There is actually another property involved, the Keyboard property. With the Keyboard property on the Entry, you can control what kind of (software) keyboard is shown when the user focusses an input box. For instance, you can set it to numeric and the keyboard that pops up for that input field will be focussed on the user entering just numeric values. An example (of the actual bug) can be shown in the image underneath.
Keyboard shown in numeric mode on UWP
With the IsPassword property, you can toggle whether the contents of the input field are obfuscated. Typically used when the user has to input a password. What then happened was this: the keyboard was set to numeric and when the IsPassword property was then toggled, the keyboard value was reset to normal, losing the numeric (or whatever you wanted it to be) setting.
As you can see in the linked GitHub issue, there is some legacy code in the FormsTextBox.cs file. That’s right, no renderer. So, what is going on here?
UWP FormsTextBox #
Besides simply mapping the abstract Entry control onto the UWP TextBox control, the Xamarin.Forms team chose to add a FormsTextBox control in-between. What the exact motivation behind that is, honestly I don’t know, but it’s there. The “problem” with an intermediate control, is that you will have to mimic a lot of the behavior that is normally built into the control by default. For instance, setting which keyboard to be shown whenever it is a password field is something that is normally implemented by the UWP platform, but now there is some custom code in place to do this. This is also one of the reasons this bug came up.
What happened with this bug, is that the InputScope was changed for when there was a switch between a password and regular field. It was not taken into account, that there is also a password variant of the obfuscated InputScope. Normally, when using the default TextBox you can assume that this has been implemented right. But again, because of the FormsTextBox there is code in place to switch between input scopes to prevent passwords from popping up as auto suggests etc. By simply adding the code underneath, we could now preserve the keyboard settings and the bug is gone!
I hope to have given you some insights into the internals of Xamarin.Forms, and how bugs could be introduced. I really love contributing back to a framework that I work a lot with. The team and community are really helpful and kind. If you want to try it yourself, head over to the repository and start crackin’! If you need any help, you know where to find me :)