Search code examples
c#xamlxamarin.formsbindableproperty

Get value of a BindableProperty used in ViewModel in control?


I have a Control where i define a BindableProperty of type bool. This BindableProperty is used by the ViewModel: How can I get the value this property has in the ViewModel from my control?

For example, in the ViewModel I assign it false, in the control I want to get its value and if it is false, it does something.

My code

Custom Control xaml cs:

 public static readonly BindableProperty CustomEmojisProperty =
            BindableProperty.Create("CustomEmojis", typeof(bool), typeof(Editor), propertyChanged: OnPropertyChanged);

    public bool CustomEmojis
    {
        get { return (bool)GetValue(CustomEmojisProperty); }
        set { SetValue(CustomEmojisProperty, value); }
    }

    private static void OnPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {

        var editor = bindable as Editor;

        if (((Editor)bindable).CustomEmojis == false)
        {

            ObservableCollection<Emojis> EmojiList = new ObservableCollection<Emojis>();

            editor.collectionView.ItemsSource = EmojiList;

            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SlightlySmilingFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.FaceWithStuckOutTongueAndWinkingEye) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.LoudlyCryingFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.WinkingFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SmilingFaceWithHeartEyes) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.OkHand) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.ThumbsUp) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.ThumbsDown) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.UpsideDownFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.CryingFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.FaceWithColdSweat) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.FlexedBiceps) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.NeutralFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.FaceScreamingInFear) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.FaceWithTearsOfJoy) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.BackhandIndexPointingUp) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.GrinningFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.MoneyMouthFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.OpenHands) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.RaisedFist) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.RaisedHand) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.RelievedFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.PensiveFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SmilingFaceWithOpenMouth) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SmilingFaceWithOpenMouthAndSmilingEyes) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SmilingFaceWithOpenMouthAndClosedEyes) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SmilingFaceWithOpenMouthAndColdSweat) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.VulcanSaluteLightSkinTone) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SmilingFaceWithSunglasses) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.FaceWithStuckOutTongue) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.FaceWithStuckOutTongueAndClosedEyes) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.RaisingHands) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.UnamusedFace) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.IndexPointingUp) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.VictoryHand) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.WavingHand) });
            EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.SignOfTheHornsMediumLightSkinTone) });

        }
    }

Mainpage.xaml:

 <fav1:Control CustomEmojis="{Binding CustomEmojis}"/>

Mainpage.cs:

  public MainPage()
    {
        InitializeComponent();
        Xamarin.Forms.Application.Current.On<Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
        BindingContext = new EmojiViewModel();
    }

ViewModel.xaml.cs:

   public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged(string propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
  ObservableCollection<Emojis> emojilist;
        public ObservableCollection<Emojis> EmojiList
        {
            get => emojilist; set
            {
                emojilist = value;
                OnPropertyChanged();
            }
        }

        bool customemojis;
        public bool CustomEmojis {
          get =>customemojis;
          set {
            customemojis = value;
            OnPropertyChanged();
          }
        }
        
        public ViewModel() {
          CustomEmojis = true;
        
          if (CustomEmojis == true)
                {
                    EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.Niger) });
                    EmojiList.Add(new Emojis { EmojiSource = Convert.ToString(Emoji.Kiss) });
                }
        
        }

I'm not sure if this is actually possible to do, if not, is there a way to call a method created on the control in the ViewModel?


Solution

  • Use the propertyChanged property of the BindableProperty. You can modify your code as follows:

    class Control : BindableObject
        {
    
            public static readonly BindableProperty CustomEmojisProperty =
                    BindableProperty.Create("CustomEmojis", typeof(bool), typeof(Editor), propertyChanged: OnPropertyChanged);
    
            public bool CustomEmojis
            {
                get { return (bool)GetValue(CustomEmojisProperty); }
                set { SetValue(CustomEmojisProperty, value); }
            }
    
            private static void OnPropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                if (((Control)bindable).CustomEmojis == false)
                {
    
                    //do something
                }
            }
    
            
    
        }
    

    To demonstrate how this works i created a whole simple sample:

    Control.cs

    using Xamarin.Forms;
    
    namespace PickerOC
    {
    
        class Control : Label
        {
    
            public static readonly BindableProperty CustomEmojisProperty =
                    BindableProperty.Create("CustomEmojis", typeof(bool), typeof(Editor), propertyChanged: OnPropertyChanged);
    
            public bool CustomEmojis
            {
                get { return (bool)GetValue(CustomEmojisProperty); }
                set { SetValue(CustomEmojisProperty, value); }
            }
    
            private static async void OnPropertyChanged(BindableObject bindable, object oldValue, object newValue)
            {
                if (((Control)bindable).CustomEmojis == false)
    
                    await Application.Current.MainPage.DisplayAlert("Alert!", "CustomEmoj is false!", "Ok");
    
                else
    
                    await Application.Current.MainPage.DisplayAlert("Alert!", "CustomEmoj is true!", "Ok");
    
            }
    
        }
    }
    

    MainPage.xaml

    <?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:local="clr-namespace:PickerOC"
                 x:Class="PickerOC.MainPage">
    
        <StackLayout>
            <local:Control x:Name="control"
                           Text="I am the Control!"
                           Padding="20"
                           CustomEmojis="{Binding CustomEmojis}"
                           HorizontalOptions="CenterAndExpand"/>
            
            <Button Text="Change Custom Emoji!!!"
                    Clicked="Button_Clicked"/>
        </StackLayout>
    
    </ContentPage>
    

    Code behind (MainPage.xaml.cs)

    using System;
    using Xamarin.Forms;
    
    namespace PickerOC
    {
        public partial class MainPage : ContentPage
        {
    
            MainPageViewModel viewModel { get; set; }
    
            public MainPage()
            {
                InitializeComponent();
            }
    
            protected override void OnAppearing()
            {
                base.OnAppearing();
    
                viewModel = new MainPageViewModel();
                BindingContext = viewModel;
            }
    
            private void Button_Clicked(object sender, EventArgs e)
            {
    
                viewModel.CustomEmojis = !viewModel.CustomEmojis;
            }
        }
    }
    

    View Model

    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    
    namespace PickerOC
    {
        class MainPageViewModel : INotifyPropertyChanged
        {
    
            bool customemojis;
            public bool CustomEmojis
            {
                get => customemojis;
                set
                {
                    customemojis = value;
                    OnPropertyChanged();
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            public void OnPropertyChanged([CallerMemberName] string name = "")
            {
                var propertyChanged = PropertyChanged;
    
                propertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
            }
        }
    
    }
    

    If you have further issues, let us know!

    Happy codding!