Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 75885

XAML Binding within a resource dictionary (ContentPage.Resources) does not work

$
0
0

I am creating a form using MVVM. In general it works, however I want to bind the Command property of each item in a ListView control to an ICommand on the view model, shown below (the property I need to bind to being the "NavigateCommand" property)...

    public class HomePageViewModel {

        private Command<Type> navigateCommand;
        private ObservableCollection<Menu> menus;

        public Command<Type> NavigateCommand {
            get {

                if (this.navigateCommand == null)
                    this.navigateCommand = new Command<Type>(async (Type type) => {

                        Page page = (Page)Activator.CreateInstance(type);
                        await Application.Current.MainPage.Navigation.PushAsync(page);

                    });

                return this.navigateCommand;
            }
        }

        public ObservableCollection<Menu> Menus {
            get {

                if (this.menus == null) {

                    this.menus = new ObservableCollection<Menu> {
                    };

                }

                return this.menus;

            }
        }

        public class Menu {

            public ObservableCollection<MenuItem> MenuItems { get; set; }

            public String Title { get; set; }

        }

        public class MenuItem {

            public String Detail { get; set; }

            public Object ImageSource { get; set; }

            public Type PageType { get; set; }

            public String Text { get; set; }

        }

    }

In order to achieve this, I have adapted a technique that I have used many times in WPF; I have created what I call a "CommandReference" object that can be created as a page level resource with a reference to the original command and then bound to within the form as a static resource...

    public class CommandReference : BindableObject, ICommand {

        public static readonly BindableProperty CommandProperty = 
            BindableProperty.Create("Command", typeof(ICommand), typeof(CommandReference),
            defaultValue: null, propertyChanged: CommandReference.OnCommandChanged);

        public ICommand Command {
            get { return (ICommand)GetValue(CommandReference.CommandProperty); }
            set { SetValue(CommandReference.CommandProperty, value); }
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter) {
            if (Command != null)
                return Command.CanExecute(parameter);
            return false;
        }

        public void Execute(object parameter) {
            if (this.CanExecute(parameter)) {
                Command.Execute(parameter);
            }
        }

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

            CommandReference commandReference = bindable as CommandReference;
            ICommand oldCommand = oldValue as ICommand;
            ICommand newCommand = newValue as ICommand;

            if (oldCommand != null)
                oldCommand.CanExecuteChanged -= commandReference.CanExecuteChanged;

            if (newCommand != null)
                newCommand.CanExecuteChanged += commandReference.CanExecuteChanged;

        }

    }

I then add this to my XAML...

    <?xml version="1.0" encoding="utf-8" ?>
    <xlfc:ExtendedTabbedPage x:Class="xx.Views.HomePage"
        xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:local="clr-namespace:xx"
        xmlns:viewModels="clr-namespace:xx.ViewModels"
        xmlns:views="clr-namespace:xx.Views"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:xlfc="clr-namespace:XLabs.Forms.Controls"
        ItemsSource="{Binding Menus}"
        Title="{x:Static local:Constants.ApplicationTitle}">

        <ContentPage.Resources>
            <ResourceDictionary>
                <views:CommandReference x:Key="navigateCommand"
                    Command="{Binding NavigateCommand}"/>
            </ResourceDictionary>
        </ContentPage.Resources>

        <ContentPage.BindingContext>
            <viewModels:HomePageViewModel />
        </ContentPage.BindingContext>

        <xlfc:ExtendedTabbedPage.ItemTemplate>
            <DataTemplate>
                <ContentPage Title="{Binding Title}">
                    <ListView HorizontalOptions="StartAndExpand"
                        ItemsSource="{Binding MenuItems}"
                        VerticalOptions="StartAndExpand">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <ImageCell Command="{StaticResource navigateCommand}"
                                    CommandParameter="{Binding PageType}"
                                    Detail="{Binding Detail}"
                                    ImageSource="{Binding ImageSource}"
                                    Text="{Binding Text}"/>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </ContentPage>
            </DataTemplate>
        </xlfc:ExtendedTabbedPage.ItemTemplate>

    </xlfc:ExtendedTabbedPage>

All works well from a UI binding perspective with the tabs and menus being displayed as expected and the binding from the ImageCell to the CommandReference being exactly as expected, however when the CommandReference instance is created it is never bound to the "NavigationCommand" property of the view model. I do not understand why this is the case.

Can any body therefore explain why the binding (during instantiation of the CommandReference object as a page resource) is never actioned?

I am using Xamarin.Forms version 1.4.3.6376 if that makes a difference and I have tested this on both Android and Windows so far.

Thanks for any help you can offer.

Martin.


Viewing all articles
Browse latest Browse all 75885

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>