⬆️ ⬇️

Features of development for Xamarin.Forms

About a year ago, a cross-platform framework called Xamarin.Forms appeared. It allows you to create mobile applications for different platforms using C # and .NET. In fact, it is an add-on over the already existing Xamarin.iOS, Xamarin.Android and Xamarin.WinPhone. And, unlike them, it allows you to create only one project in which you can describe the entire logic of the application and its UI. And then just compile it for different platforms. In the end, all this saves a lot of time.



We believe that this platform has its prospects and, therefore, could not pass by it. By tradition, we started with the development of Data Grid controls. During the work on it we have accumulated an interesting development experience for Xamarin.Forms, and we want to share it with you.



This article is based on my report on DevCon 2015, and those who wish can familiarize themselves with the video version here .



Benefits of Xamarin.Forms



To begin, I would like to talk about the benefits of this platform:



')

Features and disadvantages of Xamarin.Forms



Let's now move on to the nuances and disadvantages.



For a start, a little technical introduction. In the following diagram, I’ve roughly shown how Xamarin.Forms works.







At the top of the circuit is the PCL part. In essence, this is Xamarin.Forms. In general terms, it is a set of editors, navigation bars, layout panels and so on. When developing a UI, you work with them most of the time. However, these controls are just an abstraction inside the PCL part. So that they could somehow be displayed on the device, there are so-called renderers. They are located on the next level of the hierarchy in the Xamarin Platform parts.



Under the PCL part we have Xamarin.iOS, Xamarin.Android and Xamarin.WinPhone. This is essentially the Xamarin that already existed before Xamarin.Forms. And what is this Xamarin? These are C # wrappers over native classes for each platform. So renderers are such wrappers over the corresponding visual components, but which additionally contain references to PCL objects inside themselves, can read the properties they have and apply them to themselves.



In the future, these renderers are already deployed to native controls. We can see them at the bottom level of the scheme.



That there was less confusion, I will give an example. There is a Button class in the PCL part. Each Xamarin Platform part contains a ButtonRenderer class that stores an instance of the Button class. In turn, ButtonRenderer's are wrappers over classes of buttons for each platform, for example, UIButton in iOS. It is along such a chain that work with controls from the PCL part takes place.



It is in this mechanism that almost all the problems of this platform are concluded.



We can distinguish the following groups of problems encountered in the development of Xamarin.Forms:





Now let's look at these problems with specific examples.



Incomplete implementation of WPF functionality



This is the first thing we stumbled upon. Xamarin.Forms has significant limitations in the use of templates during development. As a person who has worked with WPF for a long time, I really like this tool. Since it is very convenient when you can arbitrarily change the appearance of the control by simply overlapping the template. However, it is clear that templates do not fit into the concept of renderers, because on the end platforms this is only possible in WinPhone.



Tradeoffs in the implementation of functional, which differs on different platforms



Platforms sometimes differ, and renderers have to reduce all these differences to some kind of unified management mechanism. Thus, one has to sacrifice some functionality.





Different behavior on different platforms



Sometimes the behavior of controls can vary on different platforms. As you have already seen, in Xamarin.Forms the user interface is described in a common part for all platforms. And it is expected that in the end it will look the same on all systems. Well, or at least very close. But this is not always the case. Let's go through the main rake, which we attacked.



Margins in WinPhone


In WinPhone, some controls have large margins, which is not available on other platforms (for example, the Switch controls). Thus, the appearance of the application on it can be very different from the versions on Android and iOS, up to a complete inoperability (when the elements simply do not fit in the visible area).



I will show a small example. If you create a test application with a similar layout:

<Grid RowSpacing="0"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Switch Grid.Row="0“ /> <Switch Grid.Row=“1“ /> </Grid> 




and then run it under iOS, we get the following appearance:







On Android will be the same. But if we run it under WinPhone, we get the following result:







As you can see, the Switch controls are located at a distance from each other. The reason for this is that inside the Switch control in WinPhone there is a Grid panel that is too large. Since this behavior is specific under WinPhone, this should be solved not at the PCL level, but in the switch renderer. A native solution under WinPhone would be overlapping the default style for Switch controls, or overlapping styles only for the required switches. It is clear that in the PCL part we will not be able to do this and it is necessary to go one level lower in Xamarin.WinPhone.



At the Xamarin.WinPhone level, we can set a new default style, but we cannot apply the style only for the controls we need. Since we had to change the appearance of only those switches that are inside the grid, and not touch the rest, let's solve this problem.



As I wrote above, at the platform level, the controls are represented by their renderers. So, to make any changes to the control, you need to edit its renderer. Since now our task is to correct the behavior of our switches only and not to affect the others, the simplest solution is to make the switch heir (and use it later) and write a renderer for it (inherited from the standard ButtonRenderer). And in this renderer we can change the visual tree of the control as we like. For example:

 Control switchControl = VisualTreeHelper.GetChild(Control, 0) as Control; Border border = VisualTreeHelper.GetChild(switchControl, 0) as Border; Grid grid = VisualTreeHelper.GetChild(border, 0) as Grid; grid.Height = 40; 




And you need to remember to return the correct size in the GetDesiredSize method:

 public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) { SizeRequest result = base.GetDesiredSize(widthConstraint, heightConstraint); result.Request = new Size(result.Request.Width, 40); return result; } 




As a result, we get the result:







Interception of gestures


For the following example, suppose we have a new task: we need to block all gestures over some area of ​​the screen. There are many controls there, and some of them catch gestures on their own (for example, editors and buttons), so there is no single entry point for locking. In this case, there is a simple solution: put a transparent panel on top of the required area and set the InputTransparent property to it to false. This property is just responsible for the fact that gestures cease to prokidyvatsya further along the tree of elements. So, if we write something like this:

 <Grid> <Switch VerticalOptions="Center" HorizontalOptions="Center"/> <ContentView VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" InputTransparent="false"/> </Grid> 




then it should work and the Switch should not be pressed. And indeed in iOS, everything is happening. But if you check it in Android, then Switch will still be pressed in it. As you can see, Android ignores setting the InputTransparent property. To fix this, let's look like in the previous example - create a ContentView heir and write the following renderer for it:

 public class MyContentViewRenderer : Xamarin.Forms.Platform.Android.VisualElementRenderer<MyContentView> { public override bool DispatchTouchEvent(Android.Views.MotionEvent e) { return !Element.InputTransparent; } } 




I overlap the DispatchTouchEvent method, which is exactly responsible for making gestures, and return a value on it depending on the PCL object that is set to InputTransparent. We also solved this problem.



Default Difference in Layout


Elements can have default property values ​​for different platforms. For example, the layout. If we try to start the application with this panel:

 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="DefaultLayout.MyContentPage"> <Switch /> </ContentPage> 




then we will get these results on iOS and WinPhone:







On Android it will be the same as on WinPhone. As you can see, controls appeared in different places on the screen. Therefore, one should not always rely on default values ​​of properties. It is better to protect yourself and set their values ​​so that something like this does not work out.



Performance



Also, an additional level of abstraction of the PCL part adds new brakes to the application. According to the speed of the application on Xamarin.Forms can be quite losing native. Especially since he likes very often to redraw the entire visual tree.



How do we live with this?



As I have already shown, in order to circumvent such problems, you have to climb into the native mobile parts and write your renderers for the elements, and they have to decide what the default renderers can't handle.



Personally, we wrote our own gesture handler completely, allowing us to subscribe to any gestures from the PCL part, we wrote renderers for all editors, pulling the missing properties there. The problem with InputTransparent was again solved by the renderer in the android and the blocking of gestures in it. Well, when you climb into the renderer, you already have to deal with the native API of the system in which you are in the renderer. And this already requires studying this API. So I knowingly at the beginning mentioned that it is not necessary to learn it at first, then it will most likely come up against this anyway.



But all these problems somehow manage. And we were finally able to write our GridControl on this framework. It has a fairly large functionality for display and work with data. It looks like this:







Grid turned out quite smart and rich in functionality. But we will write more about it in our next article about Xamarin.Forms.



As an output, I want to say that Xamarin.Forms can be used when you need a quick start on several platforms at once, when performance is not very important, or when there is a lot of old code that you want to reuse in the new application. Also, it will certainly be very useful for corporate programmers, because there the speed of development is more important than the beauty of the final application.



Of course, if any unusual design or high speed of work is important to you, and you are writing applications for sale in stores, then it may be better to write in native or in Xamarin Mobile. Although currently the Xamarin team is actively developing its product, quite often there are updates. So one can hope that the scope of Xamarin.Forms will expand.



Update:

Get more information about GridControl in our article: Free Grid Control for Xamarin from DevExpress

Source: https://habr.com/ru/post/263645/



All Articles