locked
Creating badgeview using skiasharp. But value doesnot updates RRS feed

  • Question

  • User220854 posted

    I am working on a shopping app. I am using shell. I created a badgeview using skiasharp. Now I want to increase and decrease the value of badge view as per user actions. But the user actions does not propogate any changes on the UI. My XAML file is -

    `

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
    
        <StackLayout Orientation="Horizontal" HorizontalOptions="Center">
            <Button Text="-" FontSize="Large" Padding="0" Command="{Binding DecrementCommand}" CommandParameter="FirstControl"></Button>
            <Label Text="{Binding FirstControlCount, StringFormat='{0}'}" VerticalOptions="Center"></Label>
            <Button Text="+" FontSize="Large" Padding="0" Command="{Binding IncrementCommand}" CommandParameter="FirstControl"></Button>
        </StackLayout>
    
         <StackLayout Grid.Row="1" Orientation="Horizontal" HorizontalOptions="Center">
            <Button Text="-" FontSize="Large" Padding="0" Command="{Binding DecrementCommand}" CommandParameter="SecondControl"></Button>
            <Label Text="{Binding SecondControlCount, StringFormat='{0}'}" VerticalOptions="Center"></Label>
            <Button Text="+" FontSize="Large" Padding="0" Command="{Binding IncrementCommand}" CommandParameter="SecondControl"></Button>
        </StackLayout>
    </Grid>
    

    `

    The ViewModel class is -

    `using System; using System.Threading.Tasks; using System.Windows.Input; using ReactiveUI.Fody.Helpers; using Xamarin.Forms;

    namespace BadgeSkiaSample.ViewModels { public class MainViewModel { public ICommand IncrementCommand { get; set; } public ICommand DecrementCommand { get; set; }

        [Reactive]
        public int FirstControlCount { get; set; }
        [Reactive]
        public int SecondControlCount { get; set; }
        [Reactive]
        public int TotalCount => FirstControlCount + SecondControlCount;
    
        public MainViewModel()
        {
            IncrementCommand = new Command<string>( (parameter)=> IncreaseCount(parameter));
            DecrementCommand = new Command<string>((parameter)=>  DecreaseCount(parameter));
        }
    
        private void DecreaseCount(string parameter)
        {
            if (parameter == "FirstControl")
            {
                --FirstControlCount;
                return;
            }
    
            --SecondControlCount;
        }
    
        private void IncreaseCount(string parameter)
        {
            if (parameter == "FirstControl")
            {
              FirstControlCount++;
                return;
            }
    
            ++SecondControlCount;
    
        }
    }
    

    }`

    Finally the BadgeView is defined in separate class-

    `using SkiaSharp; using SkiaSharp.Views.Forms; using Xamarin.Forms; using ReactiveUI.Fody.Helpers;

    namespace BadgeSkiaSample.Controls { public class BadgeView : SKCanvasView { public static readonly BindableProperty BadgeColorProperty = BindableProperty.Create(nameof(BadgeColor), typeof(SKColor), typeof(BadgeView), SKColors.Red); public static readonly BindableProperty TextColorProperty = BindableProperty.Create(nameof(TextColor), typeof(SKColor), typeof(BadgeView), SKColors.White); public static readonly BindableProperty BadgeValueProperty = BindableProperty.Create(nameof(BadgeValue), typeof(int), typeof(BadgeView), 0, defaultBindingMode: BindingMode.TwoWay, propertyChanged: OnBadgeValueChanged);

        private static void OnBadgeValueChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var view = bindable as BadgeView;
            view?.InvalidateSurface();
    
        }
    
        [Reactive]
        public SKColor BadgeColor
        {
            get => (SKColor)GetValue(BadgeColorProperty);
            set => SetValue(BadgeColorProperty, value);
        }
    
        [Reactive]
        public SKColor TextColor
        {
            get => (SKColor)GetValue(TextColorProperty);
            set => SetValue(TextColorProperty, value);
        }
    
        [Reactive]
        public int BadgeValue
        {
            get => (int)GetValue(BadgeValueProperty);
            set => SetValue(BadgeValueProperty, value);
        }
    
    
    
        SKPaint textPaint = new SKPaint
        {
            TextSize = 18,
            IsAntialias = true,
            Color = SKColors.White,
    
        };
    
    
        SKPaint circleFillPaint = new SKPaint
        {
            Style = SKPaintStyle.Fill,
            Color = (Color.FromHex("#E96125")).ToSKColor(),
            IsAntialias = true
        };
    
        public BadgeView()
        {
            BindingContext = this;
            this.WidthRequest = 15;
            this.HeightRequest = 15;
        }
    
        protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
        {
            SKCanvas canvas = e.Surface.Canvas;
            canvas.Clear(SKColors.Yellow);
            canvas.DrawCircle((float)(this.Width), (float)this.Height, 15, circleFillPaint);
            canvas.DrawText(BadgeValue.ToString(), 6, 20, textPaint);
        }
    }
    

    }`

    Please find attached the project file.

    Wednesday, December 25, 2019 10:12 AM

Answers

  • User382871 posted

    I want to increase and decrease the value of badge view ... But the user actions does not propogate any changes on the UI I've tested your code, to update the value, the Model class should inherit from INotifyPropertyChanged. Implementing this interface in a view model or model class allows the class to provide change notifications to any data-bound controls in the view when the underlying property value changes. Tutorial. ``` public class MainViewModel : INotifyPropertyChanged { public ICommand IncrementCommand { get; set; } public ICommand DecrementCommand { get; set; }

    //[Reactive]
    //public int FirstControlCount { get; set; }
    
    public int firstControlCount;
    public int FirstControlCount
    {
        get
        {
            return firstControlCount;
        }
        set
        {
            if (firstControlCount != value)
            {
                firstControlCount = value;
                NotifyPropertyChanged();
            }
        }
    }
    //[Reactive]
    //public int SecondControlCount { get; set; }
    
    public int secondControlCount;
    public int SecondControlCount
    {
        get
        {
            return secondControlCount;
        }
        set
        {
            if (secondControlCount != value)
            {
                secondControlCount = value;
                NotifyPropertyChanged();
            }
        }
    }
    
    [Reactive]
    public int TotalCount => FirstControlCount + SecondControlCount;
    
    public MainViewModel()
    {
        IncrementCommand = new Command<string>((parameter) => IncreaseCount(parameter));
        DecrementCommand = new Command<string>((parameter) => DecreaseCount(parameter));
    }
    
    private void DecreaseCount(string parameter)
    {
        if (parameter == "FirstControl")
        {
            --FirstControlCount;
            return;
        }
    
        --SecondControlCount;
    }
    
    private void IncreaseCount(string parameter)
    {
        if (parameter == "FirstControl")
        {
            FirstControlCount++;
            return;
        }
    
        ++SecondControlCount;
    }
    
    protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    

    } ```

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, December 25, 2019 1:41 PM

All replies

  • User220854 posted

    For some unknown reason the BindingContext and TitleView code is not visible in the question-

     <ContentPage.BindingContext>
            <viewmodels:MainViewModel/>
        </ContentPage.BindingContext>
    
         <Shell.TitleView>
               <StackLayout VerticalOptions="Center">
                   <controls:BadgeView  BadgeValue="{Binding TotalCount,StringFormat='{0}'}"  HorizontalOptions="Center"></controls:BadgeView>
                   <Label Text="Badge" HorizontalOptions="Center"/>
               </StackLayout>
    
           </Shell.TitleView>
    
    Wednesday, December 25, 2019 1:00 PM
  • User382871 posted

    Try to use Syncfusion.Xamarin.SfBadgeView plugin to add the badges. Binding the BadgeText property to update the values.

    <badge:SfBadgeView HorizontalOptions="Center" VerticalOptions="Center" BadgeText="20"> <badge:SfBadgeView.Content> <Button Text="Primary" WidthRequest="120" HeightRequest="60"/> </badge:SfBadgeView.Content> </badge:SfBadgeView>

    Check the Tutorial: https://help.syncfusion.com/xamarin/badge-view/getting-started

    Wednesday, December 25, 2019 1:17 PM
  • User382871 posted

    I want to increase and decrease the value of badge view ... But the user actions does not propogate any changes on the UI I've tested your code, to update the value, the Model class should inherit from INotifyPropertyChanged. Implementing this interface in a view model or model class allows the class to provide change notifications to any data-bound controls in the view when the underlying property value changes. Tutorial. ``` public class MainViewModel : INotifyPropertyChanged { public ICommand IncrementCommand { get; set; } public ICommand DecrementCommand { get; set; }

    //[Reactive]
    //public int FirstControlCount { get; set; }
    
    public int firstControlCount;
    public int FirstControlCount
    {
        get
        {
            return firstControlCount;
        }
        set
        {
            if (firstControlCount != value)
            {
                firstControlCount = value;
                NotifyPropertyChanged();
            }
        }
    }
    //[Reactive]
    //public int SecondControlCount { get; set; }
    
    public int secondControlCount;
    public int SecondControlCount
    {
        get
        {
            return secondControlCount;
        }
        set
        {
            if (secondControlCount != value)
            {
                secondControlCount = value;
                NotifyPropertyChanged();
            }
        }
    }
    
    [Reactive]
    public int TotalCount => FirstControlCount + SecondControlCount;
    
    public MainViewModel()
    {
        IncrementCommand = new Command<string>((parameter) => IncreaseCount(parameter));
        DecrementCommand = new Command<string>((parameter) => DecreaseCount(parameter));
    }
    
    private void DecreaseCount(string parameter)
    {
        if (parameter == "FirstControl")
        {
            --FirstControlCount;
            return;
        }
    
        --SecondControlCount;
    }
    
    private void IncreaseCount(string parameter)
    {
        if (parameter == "FirstControl")
        {
            FirstControlCount++;
            return;
        }
    
        ++SecondControlCount;
    }
    
    protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    

    } ```

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, December 25, 2019 1:41 PM
  • User220854 posted

    @Jarvan Thanks for pointing out the cause of the issue. Actually the Reactive attribute is for Notifying property Changed. But I need to use the base class ReactiveObject for that functionality. After using ReactiveObject as base class the Properties are now notifying changes.

    Syncfusion control is a good option. But I still want to implement my own. But can't use ReactiveObject in BadgeView class as it is already derived from SKCanvasView. Any Suggestions.

    Wednesday, December 25, 2019 3:20 PM