question

XamarinNewBie-6038 avatar image
0 Votes"
XamarinNewBie-6038 asked JessieZhang-2116 edited

Custom Frame Binding Not Working

I copied/wrote a class that inherits from Frame

 public class Circle : Frame
 {
     //private double _radius;
        
     public static readonly BindableProperty RadiusProperty = BindableProperty.Create(nameof(Radius), typeof(double), typeof(Circle), 126.0, BindingMode.TwoWay);
     public double Radius
     {
         get => (double)GetValue(RadiusProperty); //_radius;
         set
         {
             SetValue(RadiusProperty, value);
             OnPropertyChanged();
             AdjustSize();
         }
     }

     private void AdjustSize()
     {
         HeightRequest = Radius;
         WidthRequest = Radius;
         Margin = new Thickness(0,0,0,0);
         Padding = new Thickness(0, 0, 0, 0);
         CornerRadius = (float) (Radius / 2);
     }

     public Circle()
     {
         HorizontalOptions = LayoutOptions.Center;
     }
 }

The consuming page defines these BinadableProperties

     public static readonly BindableProperty InnerColorProperty = BindableProperty.Create("InnerColor", typeof(Color), typeof(CircleProgressView), defaultValue: Color.FromHex("#34495E"), BindingMode.TwoWay);
     public Color InnerColor
     {
         get => (Color)GetValue(InnerColorProperty);
         set => SetValue(InnerColorProperty, value);
     }

     public static readonly BindableProperty InnerRadiusProperty = BindableProperty.Create("InnerRadius", typeof(double), typeof(CircleProgressView), 126.0, BindingMode.TwoWay);
     public double InnerRadius
     {
         get => (double)GetValue(InnerRadiusProperty);
         set => SetValue(InnerRadiusProperty, value);
     }

And uses the Circle like so

 <components:Circle Grid.Row="0" BackgroundColor="{Binding InnerColor}" Radius="{Binding InnerRadius}" >

Alas, the bindable's setter, and hence AdjustSize(), is never called nor is the default value used. Instead of a circle I end up with a rectangle. The BackgroundColor, which is a property of Frame, binds and works fine.

If I remove the BindableProperty and leave behind a regular INotify property

 public class Circle : Frame
 {
     private double _radius;

     public double Radius
     {
         get => _radius;
         set
         {
             _radius = value;
             OnPropertyChanged();
             AdjustSize();
         }
     }

     private void AdjustSize()
     {
         HeightRequest = Radius;
         WidthRequest = Radius;
         Margin = new Thickness(0,0,0,0);
         Padding = new Thickness(0, 0, 0, 0);
         CornerRadius = (float) (Radius / 2);
     }

     public Circle()
     {
         HorizontalOptions = LayoutOptions.Center;
     }
 }


The compiler complains if I keep the InnerRadius binding

Severity Code Description Project File Line Suppression State

Error Position 17:92. No property, bindable property, or event found for 'Radius', or mismatching type between value and property. ...\Components\CircleProgressView.xaml 17

I can replace the Radius binding with a hardcoded value and it runs fine, a circle appears.

<components:Circle Grid.Row="0" BackgroundColor="{Binding InnerColor}" Radius="126" >

What's wrong with a BindableProperty in a regular C# class?
dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

JessieZhang-2116 avatar image
0 Votes"
JessieZhang-2116 answered JessieZhang-2116 edited

Hello,


Welcome to our Microsoft Q&A platform!

We can try to handle data in the property changed event of bindable property instead of the setter method of a normal property.
So ,we can use the following code instead :

    public class Circle: Frame
     {
         public static readonly BindableProperty RadiusProperty = BindableProperty.Create(nameof(Radius), typeof(double), typeof(Circle), 125.0, BindingMode.TwoWay, propertyChanged: RadiusChanged);
         public double Radius
         {
             get => (double)GetValue(RadiusProperty); //_radius;
             set => SetValue(RadiusProperty, value);
         }
         static void RadiusChanged(BindableObject bindableObject, object oldValue, object newValue)
         {
             Circle circle = bindableObject as Circle;
             circle.HeightRequest = (double)newValue;
             circle.WidthRequest = (double)newValue;
             circle.CornerRadius = (float)((double)newValue / 2);
         }
     }

And use like this:

  <controls:Circle  Radius=" 70"  BackgroundColor="Green"/>

In addition, if you want to use parent page's bindable property as the Circle's binding context, you can do like this:

 <?xml version="1.0" encoding="utf-8" ?>
 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              xmlns:controls="clr-namespace:XamarinFormsPlayground.Controls;assembly=XamarinFormsPlayground"
              x:Class="XamarinFormsPlayground.MainPage"
              x:Name="myPage"
              >
     <ContentPage.Content>
         <StackLayout>
             <controls:Circle  Radius=" 70"  BackgroundColor="Green"/>
    
             <controls:Circle  BackgroundColor="{Binding InnerColor, Source={x:Reference myPage}}" Radius="{Binding InnerRadius, Source={x:Reference myPage}}"/>
         </StackLayout>
     </ContentPage.Content>
 </ContentPage>

Note: myPage is property x:Name of current page.


Best Regards,

Jessie Zhang


If the response is helpful, please click "Accept Answer" and upvote it.


Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @XamarinNewBie-6038 ,Thanks for your support for xamarin. Best regards!

0 Votes 0 ·