Bug 34531 - BindableProperty of ImageSource type raises PropertyChanged twice in custom Views
Summary: BindableProperty of ImageSource type raises PropertyChanged twice in custom V...
Status: RESOLVED FIXED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 1.4.4
Hardware: PC Mac OS
: Normal normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2015-10-02 13:21 UTC by daniel.luberda
Modified: 2016-06-23 13:28 UTC (History)
11 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Sample project (20.83 KB, application/zip)
2015-10-02 13:48 UTC, daniel.luberda
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description daniel.luberda 2015-10-02 13:21:02 UTC
In custom views, when using ImageSource bindable properties, the PropertyChanged is raised twice! It can lead to major performance issues in custom controls using images. 

Output:
!!! HomeViewModel PropertyChanged: ShowImage, value: http://ed66d424bbb74367b326a5d9900185c4.com
!!! View PropertyChanged: Image, Image hash: 289996192, value: http://ed66d424bbb74367b326a5d9900185c4.com/
!!! View PropertyChanged: Image, Image hash: 671983716, value: http://ed66d424bbb74367b326a5d9900185c4.com/

Code:

public class App : Application
{
  public App()
  {
    // The root page of your application

    var viewModel = new HomeViewModel();

    var myView = new MyView();
    myView.SetBinding<HomeViewModel>(MyView.ImageProperty, v => v.ShowImage);

    MainPage = new ContentPage {
      BindingContext = viewModel,
      Content = myView 
    };

    viewModel.Reload();
  }

  public class MyView : View
  {
    public MyView()
    {
      PropertyChanged += (sender, e) => {
        if (e.PropertyName == MyView.ImageProperty.PropertyName)
          Console.WriteLine(string.Format("!!! View PropertyChanged: {0}, Image hash: {1}, value: {2}", 
            e.PropertyName, Image.GetHashCode(), ((UriImageSource)Image).Uri));
      };
    }

    public static readonly BindableProperty ImageProperty = BindableProperty.Create<MyView, ImageSource>(w => w.Image, null);

    public ImageSource Image
    {
      get
      {
        return (ImageSource)GetValue(ImageProperty);
      }
      set
      {
        SetValue(ImageProperty, value);
      }
    }
  }

  public class HomeViewModel : INotifyPropertyChanged
  {
    public HomeViewModel()
    {
      PropertyChanged += (sender, e) => {
        if (e.PropertyName == "ShowImage")
          Console.WriteLine(string.Format("!!! HomeViewModel PropertyChanged: {0}, value: {1}", 
            e.PropertyName, ShowImage));
      };
    }

    public void Reload()
    {
      ShowImage = "http://" + Guid.NewGuid().ToString("N") + ".com";
    }

    string showImage;
    public string ShowImage
    {
      get
      {
        return showImage;
      }
      set
      {
        showImage = value;
        OnPropertyChanged("ShowImage");
      }
    }

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    public void OnPropertyChanged(string propertyName)
    {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null) 
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  protected override void OnStart()
  {
    // Handle when your app starts
  }

  protected override void OnSleep()
  {
    // Handle when your app sleeps
  }

  protected override void OnResume()
  {
    // Handle when your app resumes
  }
}
Comment 1 Paul DiPietro [MSFT] 2015-10-02 13:38:27 UTC
If you could kindly upload a sample reproduction project considering there are other classes used in the provided example code, it would be appreciated in helping to investigate the issue.
Comment 2 daniel.luberda 2015-10-02 13:40:20 UTC
There're all classes in this code. In App.class, just make an empty project and replace APP class with this. But I'll try to make a project later.
Comment 3 daniel.luberda 2015-10-02 13:48:43 UTC
Created attachment 13180 [details]
Sample project
Comment 4 Fabien Molinet 2015-10-03 04:46:27 UTC
We are also experiencing this bug.
Please note that it can lead to real performance issues.

A forum entry lies here about it: https://forums.xamarin.com/discussion/52500/bindableproperty-of-imagesource-type-raises-propertychanged-twice-in-custom-views
Comment 5 David Strickland 2015-10-05 05:03:31 UTC
I've experienced this on almost any onbindingchanged. I don't think its limited to ImageSource or CustomViews though admittedly the performance issue might be worse with those.
Comment 6 David Strickland 2015-10-05 05:04:57 UTC
MT- replaced onbindingchanged with PropertyChanged
I've experienced this on almost any PropertyChanged. I don't think its limited
to ImageSource or CustomViews though admittedly the performance issue might be
worse with those.
Comment 7 Parmendra Kumar 2015-10-12 09:45:53 UTC
I have checked this issue able to reproduce this issue with Xamarin.Forms 1.4.4.6449 and I am not getting this issue with updated Xamarin.Forms 1.5.0.6447 and 1.5.1.6455-pre1, So I am closing this issue.

Observation with Xamarin.Forms 1.4.4.6449

Screencast: http://www.screencast.com/t/DjLVGm8YbxX
ApplicationOutput: https://gist.github.com/Parmendrak/3abab6327eb9580f0c03


Observation with Xamarin.Forms 1.5.0.6447 and 1.5.1.6455-pre1

Screencast: http://www.screencast.com/t/zNawO2irtEO
ApplicationOutput: https://gist.github.com/Parmendrak/f4b4d1aad3d959a2d321

If you still getting same issue, Please feel free to reopen this issue.

Thanks.
Comment 8 Mike 2015-12-20 13:53:20 UTC
I'm getting two notifications for property change events as well - and I just updated to the latest version of Xamarin Forms.
Comment 9 Parmendra Kumar 2015-12-21 11:08:36 UTC
@Mike,

I have checked this issue with latest stable Xamarin.Forms version 2.0.0.6490 and I am not able to reproduce this issue with latest version.

Screencast: http://www.screencast.com/t/svDi0kjc

ApplicationOutput Log: https://gist.github.com/Parmendrak/0d3aeb4de77a8223468a


Could you please provide us complete environment info?


Thanks.
Comment 10 Mike 2015-12-22 01:53:34 UTC
Unfortunately, I'm not running the code from this bug.  I tried to create the smallest possible app to reproduce this but for some reason the linker doesn't allow me to compile or test my app because of a missing default constructor.

My app is targeting minimum API level 21 and using 23 for both compile and target android version for all my projects (I've got 3 PCLs and 3 android projects).

The PCLs all use this:
[MYAPPDIR]\packages\Xamarin.Forms.2.0.0.6490\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Core.dll

The Forms version points to this (droid project)
[MYAPPDIR]\packages\Xamarin.Forms.2.0.0.6490\lib\MonoAndroid10\Xamarin.Forms.Core.dll

My Progress control class has, for example, this property that I set to true when I want my progress control to show:

        public static readonly BindableProperty ShowIndeterminateProperty =
            BindableProperty.Create<CoreProgress, bool>(
                p => p.ShowIndeterminate, default(bool));

        public bool ShowIndeterminate
        {
            get { return (bool)GetValue(ShowIndeterminateProperty); }
            set { SetValue(ShowIndeterminateProperty, value); }
        }

It seems any property I try all have the same effect - calling the OnElementPropertyChanged twice on that property.

I have breakpoints on the following 2 lines of code.  The breakpoint on ProgressControl.ProgressColor line is only hit after two calls to OnElementPropertyChanged with my ShowIndeterminate property as PropertyChangedEventArgs.PropertyName:

Breakpoint1:  ProgressControl.ShowIndeterminate = true;
Breakpoint2:  ProgressControl.ProgressColor = new Color(255, 0, 0, 255);


As long as you don't see an issue with the configuration of my PCLs or droid projects, then please look at the code more carefully.  There has to be something in there calling it twice.  I will continue to try to provide a bare-bones project that reproduces the issue.

Apologies if there's something unforeseen in something I'm doing wrong.. But I really don't think so...  I've been wrong before though...  :)

Thanks for your help!
Mike
Comment 11 Parmendra Kumar 2015-12-22 11:29:18 UTC
@Mike,

I have tried to reproduce this issue with provided instruction in comment #10, and I am not sure how to reproduce it.

Could you please provide us sample project? so that we can reproduce this issue at our end.


Thanks.
Comment 12 François M 2016-06-23 13:20:14 UTC
I also encounter that issue though I can't reproduce it with a new project :-(
Comment 13 François M 2016-06-23 13:28:15 UTC
Both my project and the sample project I wrote to reproduce the issue have the same code now but in my project OnPropertyChanged is called twice whereas in the sample project only once.
They both are on XF 2.2.0.45.
My project has many pages but I only set the same page as in my sample as the main page.