Property change not fired on bindable property defined at page level

Jefry Pozo 96 Reputation points
2021-07-03T09:58:21.99+00:00

I have a custom ContentPage with a BindableProperty called ActionBarMenu but somehow it looks like bindings are not working if you set them at the page level.

I'm trying to achieve something like the TitleView or the ToolbarItems of a page:

<controls:ContentPageWithActionBar.ActionBarMenu>        
        <actionBarMenu:Menu
            MenuDismissedCommand="{Binding DismissSelectionCommand}"
            ToolbarOffsetChangedCommand="{Binding ToolbarOffsetChangedCommand}">            
            <actionBarMenu:Menu.MenuItems>
                <actionBarMenu:MenuItem Title="My title" TooltipText="This is my title" />
                <actionBarMenu:MenuItem Title="My title2" TooltipText="This is my title 20" />
                <actionBarMenu:MenuItem Title="My title3" TooltipText="This is my title 3" />
            </actionBarMenu:Menu.MenuItems>
        </actionBarMenu:Menu>
    </controls:ContentPageWithActionBar.ActionBarMenu>

The property changed is not firing for both events, but I noticed that if I set the control as a child of another view then it's working fine.

This is the Menu.cs file:

public class Menu : View
    {
        public static readonly BindableProperty MenuItemsProperty = BindableProperty.CreateAttached(
            "MenuItems",
            typeof(ICollection<MenuItem>),
            typeof(Menu),
            null,
            BindingMode.TwoWay,
            defaultValueCreator: bindable =>
            {
                return new Collection<MenuItem>();
            } 
        );       

        public static void SetMenuItems(BindableObject bindable, ICollection<MenuItem> value)
        {
            bindable.SetValue(MenuItemsProperty, value);
        }

        public static ICollection<MenuItem> GetMenuItems(BindableObject bindable)
        {
            return (ICollection<MenuItem>) bindable.GetValue(MenuItemsProperty);
        }

        public static readonly BindableProperty MenuDismissedCommandProperty = BindableProperty.CreateAttached(
            "MenuDismissedCommand",
            typeof(ICommand),
            typeof(Menu),
            null,
            propertyChanged: MenuDismissedCommandChanged
        );

        private static void MenuDismissedCommandChanged(BindableObject bindable, object oldvalue, object newvalue)
        {

        }

        public static void SetMenuDismissedCommand(BindableObject bindable, ICommand value)
        {
            bindable.SetValue(MenuDismissedCommandProperty, value);
        }

        public static ICommand GetMenuDismissedCommand(BindableObject bindable)
        {
            return (ICommand) bindable.GetValue(MenuDismissedCommandProperty);
        }

        public static readonly BindableProperty ToolbarOffsetChangedCommandProperty = BindableProperty.CreateAttached(
            "ToolbarOffsetChangedCommand",
            typeof(ICommand),
            typeof(Menu),
            null,
            propertyChanged: ToolbarOffsetChangedCommandChanged
        );

        private static void ToolbarOffsetChangedCommandChanged(BindableObject bindable, object oldvalue, object newvalue)
        {

        }

        public static void SetToolbarOffsetChangedCommand(BindableObject bindable, ICommand value)
        {
            bindable.SetValue(ToolbarOffsetChangedCommandProperty, value);
        }

        public static ICommand GetToolbarOffsetChangedCommand(BindableObject bindable)
        {
            return (ICommand) bindable.GetValue(ToolbarOffsetChangedCommandProperty);
        }
    }

And here is the custom ContentPage:

public class ContentPageWithActionBar : ContentPage
    {
        public static readonly BindableProperty ActionBarMenuProperty = BindableProperty.CreateAttached(
            "ActionBarMenu",
            typeof(ActionBarMenu.Menu),
            typeof(ContentPageWithActionBar),
            null,
            propertyChanged: OnActionBarMenuChanged
        );

        public static void SetActionBarMenu(BindableObject bindable, ActionBarMenu.Menu value)
        {
            bindable.SetValue(ActionBarMenuProperty, value);
        }

        public static ActionBarMenu.Menu GetActionBarMenu(BindableObject bindable)
        {
            return (ActionBarMenu.Menu) bindable.GetValue(ActionBarMenuProperty);
        }

        static void OnActionBarMenuChanged(BindableObject bindable, object oldValue, object newValue)
        {
            if (bindable != null)
            {

            }
        }
  }
}
Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,380 questions
0 comments No comments
{count} votes

Accepted answer
  1. Jefry Pozo 96 Reputation points
    2021-07-03T11:24:27.793+00:00

    Looks like the binding wasn't fired because the BindingContext was null, and this was solved by binding the BindingContext to the context of the content page.

    BindingContext="{Binding Path=BindingContext, Source={x:Reference nameofcontentpage}}
    

    With that change the binding started working :)

    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.