Category Archives: Xaml

What’s wrong with those ObservableCollections and Threading?

When you are developing Apps with Xamarin.Forms you probably used ObservableCollections more than once. That’s pretty neat, because an ObservableCollection notifies the View on any changes that occur, so you don’t have to care about updating the Views.

A common use case is as follows. You have a list of items (models) that are being read from a database. The items are being transformed to ItemViewModels and added to a ObservableCollection. This ObservableCollection is bound to a ListView, which will be updated as soon as the item is being added. When you are lucky, and the whole transformation thing takes a lot of time, you will see every item being added subsequently.

ObservableCollection bound to a CollectionView

Looks awesome, you can still interact with the UI while the list is being generated. BUT .. that only works in a perfect world. There are several reasons, why creating a ListItem isn’t as easy as 1-2-3 (like in my example). Let’s say it takes 20ms or even more, to create one item. Your UI will probably freeze:

the UI blocks while filling the list

The users of your App will not like that. I don’t like it either, when an App shows such a bad behavior. But as always, it’s compilacted… The easiest (very uncommon) way to solve that problem is to even extend the time, fight fire with fire :-). Yes it’s easy to do but in my opinion bad practice.

If you ever developed with Windows Forms, you probably know of Application.DoEvents(). That gives the UI Thread time to work through the message pipe and handle keyboard presses and UI updates. There are two ways in Xamarin.Forms (probably also works in WPF) to do this, just use one of those two commands within your loop, that is adding the items to you ObservableCollection. This gives the UI enough time to redraw the screen:

await Task.Yield()
await Task.Delay(10)

   
            for (int i=0; i<100; i++)
            {
                //await Task.Delay(1);
                await Task.Yield();
                // do something that realy takes time
                DoSomething();
                Items.Add(new ItemViewModel
                {
                    Text = $"Item {i}",
                    MoreText = $"Some more text to Item {i}"
                });
            }

That works in a lot of cases, but maybe the whole process is to complex to do this. You could refactor and clean up your whole code (I would recommend that in the first place anyway). But putting the whole stuff on a new thead sound easier, and now we introduce the problem with Threading + ObservableCollection. You will probably get the following error:

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

And guess what, it’s not a problem of the ObservableCollection, the ObservableCollection actually is not thread safe (as all non-concurrent collections in .Net), but the ObservableCollection doesn’t care about the thread you make changes from. The problem is the ListView, that the Items are bound to. It assumes, that changes on the collection are made from the MainThread and just handles the UI updates. And UI updates are, as we know, thread affine, so you can only add elements to the View when you are in the same thread as it is being created on (the main thread, also called UI thread). In the current version of Xamarin they introduced a control, that can easily handle that: CollectionView. That’s the control of choice, if you encounter the problem I mentioned above.

Always prefer the usage of CollectionView instead of ListView.

What if you can’t switch to CollectionView?

One thing you can do is to call Device.BeginInvokeOnMainThread(), but be careful with that, an invoke on the MainThread is always very expensive, you should only use it when you have no other choice. (refactoring included)

for (int i = 0; i < 100; i++)
                {
                    Thread.Sleep(500);
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        Items.Add(new ItemViewModel
                        {
                            Text = $"Item {i}",
                            MoreText = $"Some more text to Item {i}"
                        });
                    });
                }

Memory Leak in Prism.Core (Xamarin.Forms)

Prism Version: 8.0.0.1909
Packages:
Prism.Unity.Forms
Prism.Forms
Prism.Core

A couple of weeks ago, we found a memory leak in one of our Xamarin Apps. Pages that get navigated to were still kept in memory, eventhough they have been removed from the NavigationStack. I tried to figure out why the pages are still being kept in memory, therefore I wrote a small program to recreate the issue (as usal I started out with the Prism Template for Xamarin Forms Apps):

  1. MainPage with MainPageViewModel – has a command to navigate to Page2 using Prism’s PageNavigationService
  2. Page2 (allocates 10MB data) and also has a ViewModel with 10MB memory allocation

Started the App, and navigated to Page2 – 9 times and back.

JetBrains dotMemory – first try

As you can see the memory consumption is going up all the time. When I trigger the Garbage Collector, some memory got freed.. But why? Easy as this – I didn’t bind the ViewModel to the View, so there was no retention path that holds the ViewModel back from being collected by the GC. The connection between the View and the ViewModel will be cut off by the Prism framework.

But what about the View – Why isn’t the View cleared from memory? Memory profiling is a little bit like searching a needle in the haystack. But JetBrains dotMemory is a great Tool and helps a lot. You can choose a specific instance, and you’ll find all objects that may be keeping it alive.

JetBrains dotMemory – Incoming References for Page2

Actually we would have to have a look at all of those references, one after the other. That’s very time consuming, and boring. But when we have closer look, we’ll see that Prism somehow looks very conspicious – the PageNavigationService, which implements INavigationService in Xamarin.Forms.

The reason why if has a reference to the page is, that it’s a PageNavigationService, that only works in connection to a specific page, so it isn’t strange that it keeps a reference to the page. But why is it still in memory? The only reference was used within the ViewModel, and that has been garbage collected. There has to be another reference, that’s why we need to have a look at the Prism Source Code, where the NavigationService is being created:

https://github.com/PrismLibrary/Prism/blob/master/src/Forms/Prism.Forms/Navigation/Xaml/Navigation.cs

public static class Navigation
{
        internal static readonly BindableProperty NavigationServiceProperty =
            BindableProperty.CreateAttached("NavigationService",
                typeof(INavigationService),
                typeof(Navigation),
                default(INavigationService));

        private static INavigationService CreateNavigationService(IScopedProvider scope, Page page)
        {
            var navService = scope.Resolve<INavigationService>();
            switch (navService)
            {
                case IPageAware pa when pa.Page is null:
                    pa.Page = page;
                    break;
                case IPageAware pa1 when pa1.Page != page:
                    return CreateNavigationService(ContainerLocator.Container.CreateScope(), page);
            }

            page.SetValue(NavigationScopeProperty, scope);
            scope.IsAttached = true;
            page.SetValue(NavigationServiceProperty, navService);

            return navService;
        }
}

I removed some lines of code, that are not imprtant. As you can see, the NavigationService is being attached to the page itself using an AttachedProperty. That’s a pretty cool solution, but the disadvantage is that AttachedProperties are nothing more than a big static Dictionary. The key of that Dictionary is the HashCode of the page (so this is a weak reference) and the value is the instance of the NavigationService (which in fact is being a static weak reference, including the BindingContext).

Update (2021/03/07) The reference of the attached property to the PageNavigationService actually is a (static) weak reference. Somehow the PageNavigationService is still bound, and the GC can’t free the memory.

A quick hack to solve that problem is to implement IDestructible within your PageViewModels (or ViewModelBase, when you use the Prism VS-template) and remove the Page-reference from the NavigationService:

public virtual void Destroy()
{
    if (NavigationService is IPageAware pageAware)
    {
        pageAware.Page = null;
    }
}
Flyout in Xamarin forms

Creating a Flyout in Xamarin.Forms

Flyouts are a pretty neat control, first introduced in Windows UWP, but there is nothing close in Xamarin.Forms which can be used on all platforms. So I decided to create one.

What is a Flyout?

from the Windows UWP documentation (https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.flyout?view=winrt-19041)

“Use a Flyout control for collecting information, for displaying more info, or for warnings and confirmations. Unlike a dialog, a Flyout does not create a separate window, and does not block other user interaction.”

So a Flyout can be attached to whatever control you want, and it will pop up as soon as the item is tapped. There are several use cases it easy fits in:
– show more details in a specific context
– ask for confirmation
– ask for more details
– …

How will the XAML look like?

<Label Text="Hello who?">
   <FlyoutBase.AttachedFlyout>
      <Flyout BackgroundColor="Red">
          <Flyout.DataTemplate>
               <DataTemplate>
                  <Label Text="Hello World!"/>
               </DataTemplate>
          </Flyout.DataTemplate>
      </FLyout>
   </FlyoutBase.AttachedFlyout>
</Label>

Looks easy to use, but still needs to be implemented.

Main Challenge: Create a layer over the current content for our Flyout

First we need to add a layer over the whole content of the page, so we can freely place a Flyout on the screen over all other controls. We can achieve that by going up the whole visual tree, find the ContentPage and kinda inject a Grid into it. A Grid is pretty easy to use, and it has the ability to have several Children that arrange in layers one over each other. We need to do this step, because we know nothing about the Layout that is used by the programmer, that created that Page.

FlyoutBase.AttachedFlyout is a AttachedProperty that we can attach to whatever control we need. After the Flyout is attached, we just need to add the TapGesture to that control.

internal class FlyoutRootGrid : Grid {}    // just a specific type, to remind it
public class FlyoutBase
    {
        #region attachedflyout property
        public static readonly BindableProperty AttachedFlyoutProperty =
            BindableProperty.CreateAttached("AttachedFlyout", typeof(Flyout), typeof(FlyoutBase), null, propertyChanged: OnAttachedFlyoutChanged);



        public static Flyout GetAttachedFlyout(BindableObject view)
        {
            return (Flyout)view.GetValue(AttachedFlyoutProperty);
        }

        public static void SetAttachedFlyout(BindableObject view, Flyout value)
        {
            view.SetValue(AttachedFlyoutProperty, value);
        }
        #endregion

        // called whenever a flyout is attached to a view
        private static async void OnAttachedFlyoutChanged(BindableObject bindable, object oldValue, object newValue)
        {
            if (bindable is View view)
            {
                await Task.Delay(1000); // we wait a little, so the view is attached to the visual tree
                // this is very weak, we need to think about a better solution here
                AttachFlyout(view);
            }
        }



        private static void AttachFlyout(View view)
        {
            // find the FlyoutRoot
            var flyoutRootGrid = CreateOrFindRootGrid(view);
            // and now attach the flyout to it as child
            var flyout = AttachFlyoutToRoot(flyoutRootGrid, view);
            // register the desture to the visual
            view.GestureRecognizers.Add(
                new TapGestureRecognizer
                {
                    NumberOfTapsRequired = 1,
                    Command = new Command(obj => ToggleFlyoutIsVisible(flyout, view))
                });
        }

        // will go through the visual tree up to the content page
        // remove the content
        // add a "FlyotRootGrid"
        // and set the removed content to it as first child
        private static FlyoutRootGrid CreateOrFindRootGrid(VisualElement view)
        {
            var flyOutRootGrid = VisualTreeHelper.FindParentElement<FlyoutRootGrid>(view);
            // maybe we already have such a control in the visual tree (perhaps we use more than one flyout)
            // so we can reuse it
            if (flyOutRootGrid == null)
            {
                // otherwise attach iot to root
                var parentPage = VisualTreeHelper.FindParentPage<ContentPage>(view);
                flyOutRootGrid = new FlyoutRootGrid();
                var oldContent = parentPage.Content;
                parentPage.Content = flyOutRootGrid;
                flyOutRootGrid.Children.Add(oldContent);
            }
            return flyOutRootGrid;
        }

        private static Flyout AttachFlyoutToRoot(FlyoutRootGrid flyoutRootGrid, View view)
        {
            // get the flyout from the attached property
            var flyout = GetAttachedFlyout(view);
            // not visible yet
            flyout.IsVisible = false;
            // add it to the root grid
            flyoutRootGrid.Children.Add(flyout);
            return flyout;
        }

        private static void ToggleFlyoutIsVisible(Flyout flyout, View view)
        {
            // align flout to the view that has been clicked
            // set IsVisible to the flyout
        }

    }

Now that the Flyout is added to the VisualTree of the ContentPage, we just need to handle the fade in and out of the Flyout. We also have to take care of placing the Flyout correctly on the screen. Therefore we need to find the screen coordinates of the tapped view and position the Flyout accordingly.

private static void ToggleFlyoutIsVisible(Flyout flyout, View view)
{
    bool setVisible = !flyout.IsVisible; // checkout the flyout is visible
    if (flyout.Content == null &amp;&amp; flyout.DataTemplate != null)
    { // when we yet have no content -> create it from datatemplate
        flyout.Content = flyout.DataTemplate.CreateContent() as View;
    }
    if (setVisible)
    {
        flyout.AlignFlyout(view);
    }
    flyout.PlayAnimation(setVisible, view);
}

I don’t just want to set the IsVisible property. Let’s do something fancy and add an animation. But first we need to find the coordinates of the tapped control. I found a solution here (https://forums.xamarin.com/discussion/66386/how-to-get-the-coordinates-where-there-is-a-control-on-the-screen) and adjusted it a little to fit my needs. The VisualTreeHelper also includes the FindParentPage-method from a previous blog post.

public static class VisualTreeHelper
    {
        public static T FindParentPage<T>(Element view)
            where T:Page
        {
            return FindParentElement<T>(view);
        }

        public static T FindParentElement<T>(Element view, Func<T,bool> predicate = null)
            where T:Element
        {
           
            if (view is T element)
            {
                if (predicate == null)
                {
                    return element;
                }
                if (predicate(element))
                {
                    return element;
                }
            }
            if (view.Parent == null)
            {
                return null;
            }
            return FindParentElement<T>(view.Parent, predicate);
        }

        public static (double X, double Y) GetScreenCoordinates(this VisualElement view)
        {
            // A view's default X- and Y-coordinates are LOCAL with respect to the boundaries of its parent,
            // and NOT with respect to the screen. This method calculates the SCREEN coordinates of a view.
            // The coordinates returned refer to the top left corner of the view.
            var screenCoordinateX = view.X;
            var screenCoordinateY = view.Y;

            var parent = (VisualElement)view.Parent;
            while (parent != null &amp;&amp; parent is VisualElement)
            {
                screenCoordinateX += parent.X;
                screenCoordinateY += parent.Y;
                parent = parent.Parent as VisualElement;
            }
            return (screenCoordinateX, screenCoordinateY);
        }
    }

Now we can put all together and implement the Flyout

public class Flyout : ContentView
    {
        public enum AnimationType { Fade, SlideVertical }
        public Flyout()
        {
            HorizontalOptions = LayoutOptions.Start;
            VerticalOptions = LayoutOptions.Start;
        }

        public AnimationType Animation { get; set; }

        public DataTemplate DataTemplate { get; set; }


        double _targetHeight = -1;
        internal async void PlayAnimation(bool setVisible, View view)
        {
            switch (Animation)
            {
                case AnimationType.Fade:
                    if (setVisible)
                    {
                        Opacity = 0;
                        IsVisible = true;
                        await this.FadeTo(1, 250);
                    }
                    else
                    {
                        await this.FadeTo(0, 250);
                        IsVisible = false;
                    }
                    break;
                case AnimationType.SlideVertical:
                    if (setVisible)
                    {
                        if (_targetHeight == -1)
                        {
                            _targetHeight = Height == -1 ? HeightRequest : Height;
                        }
                        HeightRequest = 0;
                        Content.Opacity = 0;

                        IsVisible = true;
                        var animation = new Animation(d => HeightRequest = d, 0, _targetHeight);
                        animation.Commit(this, "Flyout");
                        await Task.Delay(100);
                        await Content.FadeTo(1, 55);

                    }
                    else
                    {
                        await Content.FadeTo(0, 55);
                        var animation = new Animation(d => HeightRequest = d, Height, 0);
                        animation.Commit(this, "Flyout2");
                        await Task.Delay(250);
                        IsVisible = false;
                    }
                    break;
            }
        }

        internal void AlignFlyout(View view)
        {
            var coords = view.GetScreenCoordinates();
            Margin = new Thickness(coords.X, coords.Y + view.Height, 0, 0);
        }

    }

As always you can use and extend the code, however you like. It’s not complete yet, feel free to fix bugs or extend it.

How to find the root Page of a specific Control in Xamarin.Forms

Actually it’s very easy to achieve this. Just traverse the visual tree upwards to find the root.

 public static class VisualTreeHelper
    {
        public static ContentPage FindParentPage(Element view)
        {
            if (view is ContentPage page)
            {
                return page;
            }
            return FindParentPage(view.Parent);
        }
    }

This does what we intended to do, but… we can do better than that!
Maybe we don’t want to just find the (Content)Page, how about finding the root grid, or a parent of a specific type. We just need to take that function and convert it to a generic function, that’s all, and we are way more flexible.

public static class VisualTreeHelper
    {
        public static T FindParentPage<T>(Element view)
            where T:Page
        {
            return FindParentElement<T>(view);
        }

        public static T FindParentElement<T>(Element view)
            where T:Element
        {
           
            if (view is T page)
            {
                return page;
            }
            if (view.Parent == null)
            {
                return null;
            }
            return FindParentElement<T>(view.Parent);
        }
    }

Performance of loading Xaml dynamically in Xamarin.Forms

As I mentioned in a previous post, you can quite easily load Xaml dynamically in your Xamarin.Forms App. But how about performance? How long does it take in comparison to “regular” loading of pre-compiled Xaml.

It’s anything but easy to really measure this. We could eventually use LoadFromXaml and measure the differences. I decided to create DataTemplates and use the CreateContent() method to create the actual Control.

&lt;DataTemplate x:Key=&quot;Test1&quot;&gt;
&lt;Grid&gt;
    &lt;Grid.RowDefinitions&gt;
        &lt;RowDefinition Height=&quot;auto&quot; /&gt;
        &lt;RowDefinition Height=&quot;*&quot; /&gt;

    &lt;/Grid.RowDefinitions&gt;
    &lt;Label Text=&quot;Hello World!&quot; /&gt;
    &lt;Button Grid.Row=&quot;1&quot; Text=&quot;Press me&quot; /&gt;
&lt;/Grid&gt;
&lt;/DataTemplate&gt;
&lt;DataTemplate x:Key=&quot;Test2&quot;&gt;
    &lt;dynamiccontrol:XamlView&gt;
        &lt;dynamiccontrol:XamlView.Xaml&gt;
            &lt;![CDATA[
            &lt;Grid&gt;
                &lt;Grid.RowDefinitions&gt;
                    &lt;RowDefinition Height=&quot;auto&quot; /&gt;
                    &lt;RowDefinition Height=&quot;*&quot; /&gt;

                &lt;/Grid.RowDefinitions&gt;
                &lt;Label Text=&quot;Hello World!&quot; /&gt;
                &lt;Button Grid.Row=&quot;1&quot; Text=&quot;Press me&quot; /&gt;
            &lt;/Grid&gt;
            ]]&gt;
        &lt;/dynamiccontrol:XamlView.Xaml&gt;
    &lt;/dynamiccontrol:XamlView&gt;
           
&lt;/DataTemplate&gt;

You can see that the Xaml is quite easy, but loading it dynamically takes over 20 times longer than compiled Xaml.

I tried to create 10,000 controls and measured the following values:
Compiled Xaml: 5.8s
Dynamic Xaml: 133.1s

I know the test is not very representative, but you should always keep in mind that there may be a performance problem when using this method. Especially when you want to create dynamic Layouts in ListViews.

You can slightly boost performance (5-10%), when you load the whole DataTemplate from Xaml, and then create the Control with it.

Dynamic DataTemplate: 124s

Dynamically create controls in Xamarin Forms

This is a very broad topic. You can actually always dynamically create controls in code behind, by just adding them to the UI during runtime. This is very easy, but it’s not generic at all, you need to code everything you would actually do in Xaml.

Another solution (which I actually prefer) is to use a ListLayout (maybe a Bindable StackLayout) and use a TemplateSelector to switch between pre defined DataTemplates based on the ViewModel, that is being used. But this will actually not give you more flexibility, but it’s definitely a better solution than the first shot.

We actually want something really flexible, we try to achieve instanciating an unknown Xaml from whatever source we have (Text, Internet, UserInput,.. ), and even provide binding to further use the UserInput in ViewModel. So there are 2 parts to this:
1. load xaml during runtime,
2. somehow achieve binding.

When you have a look in your obj-folder of a compiled Xamarin app, you will find a file called something like “MainPage.xaml.g.cs”

[global::Xamarin.Forms.Xaml.XamlFilePathAttribute("MainPage.xaml")]
    public partial class MainPage : global::Xamarin.Forms.ContentPage {
        
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "2.0.0.0")]
        private void InitializeComponent() {
            global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage));
        }
    }

There is another overload of the global extension function Xamarin.Forms.Xaml.Extensions.LoadFromXaml(..) which takes a string representation of your xaml to create a control.

We can use this, to create a ContentControl with a BindableProperty, which creates the given Xaml at runtime.

public class XamlView : ContentView
{
       
    public static readonly BindableProperty XamlProperty =
                            BindableProperty.Create(nameof(Xaml), typeof(string), typeof(XamlView), propertyChanged: OnXamlChanged);

    private static void OnXamlChanged(BindableObject bindable, object oldValue, object newValue)
    {
        try
        {
            var xamlView = (XamlView)bindable;
            ContentView view = new ContentView();
            // we add the default xaml namespace to our surrounding ContentView,
            // so it doesn't need to be defined in xaml
            view = view.LoadFromXaml("" +
                (xamlView.Xaml ?? string.Empty) +
                "");
            xamlView.Content = view;
        }
        catch (Exception ex)
        {
            // we should actually handle that exception, maybe put it on the screen as label
        }
    }

    public string Xaml
    {
        get =&gt; (string)GetValue(XamlProperty);
        set =&gt; SetValue(XamlProperty, value);
    }
}

usage:

&lt;Grid BackgroundColor=&quot;Red&quot;&gt;
    &lt;Grid.RowDefinitions&gt;
        &lt;RowDefinition Height=&quot;*&quot; /&gt;
        &lt;RowDefinition Height=&quot;*&quot; /&gt;
    &lt;/Grid.RowDefinitions&gt;
    &lt;Entry x:Name=&quot;XamlEditor&quot; Text=&quot;{Binding ContentXaml}&quot; /&gt;
    &lt;dynamiccontrol:XamlView
        Grid.Row=&quot;1&quot;
        Xaml=&quot;{Binding ContentXaml}&quot; /&gt;
&lt;/Grid&gt;

You could also bind the XamlView.Xaml directly to an Entry.Text using ReferenceBinding, but I prefer using a ViewModel instead.

And this is how it looks like:
XamlView

In my next post, I will talk about binding the Data from the XamlView to a ViewModel.

Move Controls in Xamarin.Forms App with your finger

…or Mouse.. or Pen.. or nose, whatever you like. In WPF this is very easy accomplished, because Drag&Drop is a main UI feature in Windows. Each OS implements this feature slightly different, that’s why there is no such generic solution for all platforms. Microsoft proposes a solution called TouchEffect, which implements a specific Effect for each platform. (https://docs.microsoft.com/de-de/xamarin/xamarin-forms/app-fundamentals/effects/touch-tracking)

But there is still another and quite simple solution, you can use gestures (esp. the PanGesture) for that, with slight limitations.

MoveViewXamarin

The PanGesture

The PanGesture is actually a touch based Drag&Drop. You put the finger down on the screen and moved it around until you raise your finger. The PanGesture will always fire it’s event while the finger is moving around and will be quitted with the coordinates (0,0)

The Implementation

The implementation is quite simple, actually there are only a few lines of code:
1. when panning starts: save current Translation of View
2. while panning: set translation to the starting value + panning value
3. when panning finished: reset variable for starting value

Developers are lazy people, we don’t want to copy that implementation on every View. So the trick is, to use an attached property, so we can use it on every View and even bind it to a ViewModel.

The Code

public static class MoveView
{
    #region attached properties: CanMove
    public static readonly BindableProperty CanMoveProperty =
            BindableProperty.CreateAttached("CanMove", typeof(bool), typeof(View), false,
                propertyChanged: OnCanMoveChanged);

    private static void OnCanMoveChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if ((bool)newValue &amp;&amp; bindable is View view)
        {
            PanGestureRecognizer pangest = new PanGestureRecognizer();
            pangest.PanUpdated += Pangest_PanUpdated;
            view.GestureRecognizers.Add(pangest);
        }
    }
    public static bool GetCanMove(BindableObject bindable)
    {
        return (bool)bindable.GetValue(CanMoveProperty);
    }

    public static void SetCanMove(BindableObject bindable, bool value)
    {

        bindable.SetValue(CanMoveProperty, value);
    }
    #endregion

    // saves the translation state on start, it's okay to have it static
    // because we can only move one item at a time
    static Point? _translationStart = null;
    private static void Pangest_PanUpdated(object sender, PanUpdatedEventArgs e)
    {
        if (sender is View view)
        {
            if (e.TotalX == 0 &amp;&amp; e.TotalY == 0)
            {
                // movement has end, reset
                _translationStart = null;
            }
            else
            {
                if (_translationStart == null)
                {
                    (view.Parent as Layout)?.RaiseChild(view);
                    _translationStart = new Point(view.TranslationX, view.TranslationY);
                }
                view.TranslationX = e.TotalX + _translationStart.Value.X;
                view.TranslationY = e.TotalY + _translationStart.Value.Y;
            }

        }
    }
}

Usage

 &lt;Frame BorderColor="Red" BackgroundColor="Bisque"
                   dashboard:MoveView.CanMove="True"
                   HeightRequest="100" VerticalOptions="Center"
                 /&gt;

Limitations

– only when the parent is a layout, it will raise the View that is moved to the topmost position (only in respect to the parent, not overall)
– you can simply move the View outside of its parent, but then you will not be able to move it back in

Please feel free to use the code and change it as you like. If you find bugs, you may fix them. I would also be happy if you leave me some notes.

Xamarin.Forms FlowLayout

Motivation

I recently faced the challenge to add Items of different sizes to a Page on a Xamarin.Forms App. The result should be some kind of a Dashboard with Diagrams and info boxes on it. Some diagrams are smaller, some bigger.

The first thing, that came in mind, was a FlexLayout, but this looks a little bit odd to me, because the controls on the main axis share the same size in the secondary axis. That is okay if all controls have the same height or width, but this is not the case.

FlexLayout Xamarin.Forms App

But what I actually want is something like this:

FlowLayout - Xamarin.Forms App

It’s very tough to arrange the children of a Layout, when every control has a free size defined. To solve this problem, we need to divide the available area in uniform sections. Using this approach, each control can define it’s size in units, and will be placed on the next available free spot.

Simulator Screen Shot - iPhone 11 - 2020-02-20 at 22.30.18

The Algorithm

  1. The FlowLayout needs a UnitSizeRequested in pixels, we need to calculate how many items can fit vertically and horizontally based on a size of a unit. Afterwards we need to find the actual UnitWidth and UnitHeight so that the whole area of the control is used.
  2. There need to be two attached properties for the child elements, so each element can specify its HorizontalUnits and VerticalUnits.
  3. Finally we create an array as a representation of the FlowLayout so we can arrange the Controls on it.

The Code

using System;

using Xamarin.Forms;

namespace Dashboard
{
    public class FlowLayout : AbsoluteLayout
    {
        #region attached properties: HorizontalUnitsProperty
        public static readonly BindableProperty HorizontalUnitsProperty =
                BindableProperty.CreateAttached("HorizontalUnits", typeof(int), typeof(FlowLayout), 1);
        public static int GetHorizontalUnits(BindableObject view)
        {
            return (int)view.GetValue(HorizontalUnitsProperty);
        }

        public static void SetHorizontalUnits(BindableObject view, int value)
        {
            view.SetValue(HorizontalUnitsProperty, value);
        }
        #endregion
        #region attached properties: VerticalUnitsProperty
        public static readonly BindableProperty VerticalUnitsProperty =
                BindableProperty.CreateAttached("VerticalUnits", typeof(int), typeof(FlowLayout), 1);

        public static int GetVerticalUnits(BindableObject view)
        {
            return (int)view.GetValue(VerticalUnitsProperty);
        }

        public static void SetVerticalUnits(BindableObject view, int value)
        {
            view.SetValue(VerticalUnitsProperty, value);
        }
        #endregion

        #region properties
        public double UnitSizeRequested { get; set; } = 100;
        public double UnitWidth { get; private set; }
        public double UnitHeight { get; private set; }
        #endregion
       

        protected override void OnSizeAllocated(double width, double height)
        {
            // when the control allocates the size, we will arrange the children
            base.OnSizeAllocated(width, height);
            if (width&gt;0 &amp;&amp; height&gt;0)
            {
                ArrangeChildren();
            }
        }

        

        public void ArrangeChildren()
        {
            // do the calculation (step 1)
            int horizontalUnitCount = (int)(Width / UnitSizeRequested);
            int verticalUnitCount = (int)(Height / UnitSizeRequested);
            bool[,] dashArray = new bool[horizontalUnitCount, verticalUnitCount];
            UnitWidth = UnitSizeRequested + (Width % UnitSizeRequested) / horizontalUnitCount;
            UnitHeight = UnitSizeRequested + (Height % UnitSizeRequested) / verticalUnitCount;
            foreach (var child in Children)
            {
                // for each child - find the 
                var rect = FindFreeRectangle(dashArray, GetHorizontalUnits(child), GetVerticalUnits(child));
                if (rect != null)
                {
                    AbsoluteLayout.SetLayoutBounds(child, rect.Value);
                }
                else
                {
                    // this control can not be placed ... so just skip it
                    AbsoluteLayout.SetLayoutBounds(child, new Rectangle(0, 0, 0, 0));
                }

            }
        }

        private Rectangle? FindFreeRectangle(bool[,] dashArray, int xCount, int yCount)
        {
            Rectangle res;
            for (int y = 0; y  dashArray.GetLength(1)
                )
                return false;

            for (int xx = x; xx &lt; x + xCount; xx++)
            {
                for (int yy = y; yy &lt; y + yCount; yy++)
                {
                    if (dashArray[xx, yy] == true)
                        return false;
                }
            }
            // now reserve fields
            for (var xx = x; xx &lt; x + xCount; xx++)
            {
                for (var yy = y; yy &lt; y + yCount; yy++)
                {
                    dashArray[xx, yy] = true;
                }
            }
            return true;
        }

      
    }
}

Caution: This code is not complete, perhaps you can not use it with the BindableLayout-Extension. Feel free to copy the code and change it as needed. Be careful in choosing the right UnitSizeRequested, a small unit will probably result in a rather bad performance.

Usage

&lt;FlowLayout BackgroundColor="Black" &gt;
        &lt;Frame BorderColor="Yellow" BackgroundColor="Gray" CornerRadius="0" 
                FlowLayout.HorizontalUnits="1"
                FlowLayout.VerticalUnits="1"
                 /&gt;
        &lt;Frame BorderColor="Gray" BackgroundColor="HotPink" CornerRadius="0" 
                FlowLayout.HorizontalUnits="1"
                FlowLayout.VerticalUnits="1"
                 /&gt;
        &lt;Frame BorderColor="Blue" BackgroundColor="Honeydew" CornerRadius="0" 
                FlowLayout.HorizontalUnits="1"
                FlowLayout.VerticalUnits="1"
                 /&gt;
        &lt;Frame BorderColor="Red" BackgroundColor="Bisque" CornerRadius="0" 
                FlowLayout.HorizontalUnits="4"
                FlowLayout.VerticalUnits="1"
                 /&gt;
        &lt;Frame BorderColor="Green" BackgroundColor="CadetBlue" CornerRadius="0" 
                FlowLayout.HorizontalUnits="3"
                FlowLayout.VerticalUnits="3"
                 /&gt;
&lt;/FlowLayout&gt;

Adding Themes to Xamarin.Forms App

I just want to make some short notes about themes in Xamarin.Forms Apps, since there are already a lot of tutorials available online, that go way deeper.

Themes
Themes are actually ResourceDictionaries. Each atomic type you use in your XAMLs and Styles, will be defined here. Types are f.e. Color, Double (for font sizes), etc.

&lt;ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ShoppingList.Themes.DarkTheme"&gt;
    &lt;Color x:Key="BackgroundColor"&gt;#333333&lt;/Color&gt;
    &lt;Color x:Key="TextColor"&gt;#eeeeee&lt;/Color&gt;
    &lt;Color x:Key="PlaceholderTextColor"&gt;#55ffffff&lt;/Color&gt;
    &lt;Color x:Key="ControlBackground"&gt;#111111&lt;/Color&gt;
    &lt;Color x:Key="ButtonBackgroundColor"&gt;#11ffffff&lt;/Color&gt;
&lt;/ResourceDictionary&gt;

Be sure to have a code behind file for your ResourceDictionary, that calls InitializeComponent(). Otherwise this will only work on UWP (without .NET Toolchain) and no other platforms.

Styles
In most cases the styles are not part of your themes, because using themes just makes you change the look of your pages and controls, not the styling of specific controls. Perhaps styles are using the resources, that you define in your theme. Be sure to use DynamicResource for linking to the key of the resource, otherwise you can not change themes during runtime. (Restart will be needed)

&lt;ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ShoppingList.Resources.Styles"&gt;
    &lt;Style TargetType="NavigationPage"&gt;
            &lt;Setter Property="BackgroundColor" Value="{DynamicResource BackgroundColor}"/&gt;
            &lt;Setter Property="BarBackgroundColor" Value="{DynamicResource BackgroundColor}"/&gt;
            &lt;Setter Property="BarTextColor" Value="{DynamicResource TextColor}"/&gt;
            
        &lt;/Style&gt;
        &lt;Style TargetType="Label"&gt;
            &lt;Setter Property="TextColor" Value="{DynamicResource TextColor}" /&gt;
        &lt;/Style&gt;
        &lt;Style TargetType="Entry"&gt;
            &lt;Setter Property="BackgroundColor" Value="{DynamicResource ControlBackground}" /&gt;
            &lt;Setter Property="TextColor" Value="{DynamicResource TextColor}" /&gt;
            &lt;Setter Property="PlaceholderColor" Value="{DynamicResource PlaceholderTextColor}" /&gt;
        &lt;/Style&gt;
        &lt;Style TargetType="Button"&gt;
            &lt;Setter Property="TextColor" Value="{DynamicResource TextColor}" /&gt;
            &lt;Setter Property="BackgroundColor" Value="{DynamicResource ButtonBackgroundColor}" /&gt;
            
        &lt;/Style&gt;
&lt;/ResourceDictionary&gt;

Changing the theme
Now you just need to add the following code to your App.xam.cs, then you can just call App.SetTheme(typeof(DarkTheme)) to change the theme during runtime.

Be sure to add all your style-ResourceDictionaries and a standard theme to your App.xaml in the Application.Resources-Section

internal static void SetTheme(Type themeType)
{
   Preferences.Set("Theme", themeType.FullName);
   var resDict = (ResourceDictionary)Activator.CreateInstance(themeType);
   App.Current.Resources.MergedDictionaries.Add(resDict); // this line replaces all keys of the current dictionary with the value of the selected dictionary, only the keys that are present in the selected dictionary will be replaced
}

In your “OnInitialize” method of your App.xaml.cs you can put the following code, to load the saved theme on startup:

if (Preferences.ContainsKey("Theme"))
{
   var themeTypeName = Preferences.Get("Theme",null);
   var themeType = Type.GetType(themeTypeName);
   if (themeType != null)
   {
      SetTheme(themeType);
   }
}