Xamarin Frame and disappearing Outline

This is another article in mini series of Xamarin bugs and workarounds for them 🙂 Previous one you can find here.

This one is again about Frame control. I promise that another one will be about something else B)

Issue can be observed when you bind BackgroundColor property of Frame control and something will trigger change of view model source property binded to background color.

But since one image is more than thousand words – here is gif with this bug.

Frame is quite big, but if you look near corners of it, you will see, that there are round when background is green and when background change to Red, they disappear. Outline disappear too. It is slight white line around green field (it is even less visible), but I assure you that it is there. 🙂

Ok here is a code for this example in xaml App file:

<?xml version="1.0" encoding="utf-8" ?>
<Application 
             
             x_Class="FrameBug.App">
  <Application.MainPage>
    <ContentPage>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="*"></RowDefinition>
          <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <StackLayout Padding="10">
          <Frame VerticalOptions="Center" OutlineColor="White" 
                 BackgroundColor="{Binding LineColor}">
            <Label Text="Label" FontSize="60" />
          </Frame>
        </StackLayout>
        <Button Text="Change color" Grid.Row="1" Command="{Binding ChangeColor}"></Button>
      </Grid>
    </ContentPage>
  </Application.MainPage>
</Application>

One noticable thing done in code behind for this xaml file is adding BindingContext instance (App.xaml.cs file):

namespace FrameBug
{
    public partial class App
    {
        public App()
        {
            InitializeComponent();
            BindingContext = new AppViewModel();
        }
    }
}

Ok. One missing piece is AppViewModel class:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Forms;

namespace FrameBug
{
    public class AppViewModel : INotifyPropertyChanged
    {
        private ICommand _changeColor;

        public event PropertyChangedEventHandler PropertyChanged;

        public ICommand ChangeColor => _changeColor ?? (_changeColor = new Command(OnChangeColor));

        public Color LineColor { get; set; } = Color.Green;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private void OnChangeColor()
        {
            LineColor = Color.Red;
            OnPropertyChanged("LineColor");
        }
    }
}

As you may notice it is C# code from VS2015. It will not work in prior versions, but there is not really point in doing test Xamarin apps in earlier versions since Xamarin recently was released for free even in VS2015 community edition.

With this simple application added to Xamarin template solution we can reproduce bug as in above gif. But how to fix it? And why it occurs? It took some digging and Resharper help with decompiling FrameRenderer to find out why. Yes, this class that renders Frame control as plain bitmap in Android environment is source of the problem. This class (since there is no public source code I will not include disassembled source code) have private UpdateBackground method which creates custom class based on Android Drawable class. It in its bowels it renders Background with solid color from BackgroundColor property of Frame control and Outline as a line (or rather rounded rectangle) from OutlineColor property of Frame. Those methods suppose to work either on initialization or BackgroundColor, OutlineColor properties change according to code of mentioned class. All good, right? When I created very similar class, attached it to custom renderer of Frame both operations was performed correctly during debugging session. But still frame was drawn incorrectly. It took some experimentation with height and width of rectangles in bitmap and it struck me that nothing happens even with 1×1 px size, because background is rerendered in some other place. Where? Since no more code in renderer was touching drawing it had to be in base class – VisualElementRenderer<>. If you disassemble it too, you will see that it have SetBackgroundColor and it was my first suspect. This method is executed on property change of control. Which one you ask? 🙂 BackgroundColor property. I did not dig any further since it is virtual method. Quick test proved my suspect guilty. Adding following override method to custom renderer fixed this problem.

public override void SetBackgroundColor(Color color)
{

}

Since code in FrameRenderer and its base class was executing correctly it probably was executing in wrong order. Probably it was missed by Xamarin Team after fixing this bug and closing this one. Or maybe this method as virtual was added after fix and tests and testers missed it? Nevertheless, writing new custom renderer based on Xamarin one fix this issue:

[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
namespace FrameBug.Droid
{
    public class FrameRenderer : Xamarin.Forms.Platform.Android.FrameRenderer
    {
        public override void SetBackgroundColor(Color color)
        {
            //base.SetBackgroundColor(color);
        }
    }
}

Commented line can be used to trigger the buggy behavior if anyone is curious enough 🙂

This is another one of mine unpleasant adventures with Xamarin framework. I hope this can be helpful and spare you some time. You can find sample application below.

FrameBug.zip (52.56 kb)

Also there is available public github repository with code for this article and other ones from Xamarin series.

4 Replies to “Xamarin Frame and disappearing Outline”

  1. Hi podbielski,
    Even i got the same issue, created renderer like you suggested but this override event(SetBackgroundColor) is not firing from renderer class

  2. And also when i try to change outline color from .cs file it throws this exception : Java.Lang.NullPointerExceptionAttempt to invoke virtual method 'boolean android.graphics.Bitmap.isMutable()' Any solution for this issue?

  3. "event(SetBackgroundColor)"
    It is not an event. Maybe you did not registered renderer?

    "'boolean android.graphics.Bitmap.isMutable()'"
    I do not know what this is about. Best check code from GitHub. I pretty sure that it may work differently with different versions of Xamarin. It may be even not longer an issue in newer versions.

  4. "'boolean android.graphics.Bitmap.isMutable()'"
    I had similar problem with different code when I had custom background bitmap created in custom FrameRenderer that derives from Xamarin FrameRenderer, but do not ever initializes properly Xamarin base class. Basically OnPropertyChange Xamarin base FrameRenderer object tried to change background that was not initialized and equal null.
    Solution was to use derive custom FrameRenderer from Xamarin base class of FrameRenderer, VisualElement<Frame> instead.

Leave a Reply

Your email address will not be published. Required fields are marked *

Solve : *
22 + 28 =