Search code examples
listviewxamarinxamarin.formsbindingicommand

Binding button to command inside listview dataTemplate


I came across this solution that should bind to the root page not the listview which isn't working for me (i'm trying to execute command when button pressed inside listview and pass listview item id with it) right now the (Path=BindingContext.RequestAccepted) is given Cannot resolve property "RequestAccepted" in data context of type object .

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:viewModels="clr-namespace:XamarinApp.ViewModels;assembly=XamarinApp"
         x:Name="RequestsPage"
         x:Class="XamarinApp.ViewModels.Views.CustomerTransferRequestsPage">

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

<ContentPage.Content>
    <StackLayout >
        <Label Text="لا يوجد لديك طلبات حالياً" IsVisible="{Binding EmptyLableVisible}"  ></Label>


        <ActivityIndicator IsRunning="{Binding IsLoading}" HorizontalOptions="FillAndExpand"
                           VerticalOptions="FillAndExpand"/>



        <ListView ItemsSource="{Binding RequestedItems}" 
                  HasUnevenRows="True"
                  ItemTapped="ListView_OnItemTapped"
        >

            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>

                            <Label Text="{Binding RequestUserName}"></Label>
                            <Label Text="{Binding ItemsName}"></Label>
                            <Label Text="{Binding ItemsPrice}"></Label>

                            <StackLayout Orientation="Vertical">

                                <Button Text="قبول" Command="{Binding Source={x:Reference RequestsPage}, Path=BindingContext.RequestAccepted}"></Button>
                                <Button Text="رفض"></Button>

                            </StackLayout>


                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </StackLayout>
</ContentPage.Content>

The viewModel

 public class CustomerTransferRequestsViewModel : INotifyPropertyChanged
{

  public CustomerTransferRequestsViewModel()
    {
        if (GetRequestedItems.CanExecute(null))
        {
            GetRequestedItems.Execute(null);
        }
    }
    ApiServices _apiServices = new ApiServices();

    private ObservableCollection<GetCustomerTransferOrderRespond> _requestedItems;
    private bool _emptyLableVisible;
    private bool _isLoading;

    public ObservableCollection<GetCustomerTransferOrderRespond> RequestedItems
    {
        get => _requestedItems;
        set
        {
            if (Equals(value, _requestedItems)) return;
            _requestedItems = value;
            OnPropertyChanged();
        }
    }

    public bool EmptyLableVisible
    {
        get => _emptyLableVisible;

        set
        {
            if (Equals(value, _emptyLableVisible)) return;
            _emptyLableVisible = value;
            OnPropertyChanged();
        }

    }

    public bool IsLoading { get => _isLoading; set 
        {
            if (Equals(value, _isLoading)) return;
            _isLoading = value;
            OnPropertyChanged();
        }
    }

    public ICommand GetRequestedItems
    {

        get
        {
            return new Command(async () =>
            {
                IsLoading = true;
                var accesstoken = Settings.AccessToken;
                RequestedItems = await _apiServices.GetCustomerTranferOrdersAsync(accesstoken);

                if (RequestedItems == null)
                {
                    EmptyLableVisible = true;
                    IsLoading = false;
                }
                else
                {
                    EmptyLableVisible = false;
                    IsLoading = false;
                }

            });
        }
    }


    public ICommand RequestAccepted
    {
        get
        {
            return new Command(async () =>
            {
                //RequestAccepted Logic

            });
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Solution

  • I think what you need to do is define ICommand property and assign with Command,

    Something like this in ViewModel.

    public ICommand RequestAccepted
        {
            get;
            set;
        }
    

    in constructor you can assign property with command like this,

    public CustomerTransferRequestsViewModel()
        {
            if (GetRequestedItems.CanExecute(null))
            {
                GetRequestedItems.Execute(null);
            }
            RequestAccepted = new Command(() =>
            {
                //code goes here
            });
    
        }
    

    .XAML Page

    <?xml version="1.0" encoding="utf-8"?>
    <ContentPage
        xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Name="RequestsPage"
        xmlns:local="clr-namespace:Stack51123113"
        x:Class="Stack51123113.MainPage">
        <ContentPage.BindingContext>
            <local:CustomerTransferRequestsViewModel />
        </ContentPage.BindingContext>
        <ContentPage.Content>
            <StackLayout>
                <Label
                    Text="لا يوجد لديك طلبات حالياً">
                </Label>
                <ListView
                    ItemsSource="{Binding RequestedItems}"
                    HasUnevenRows="True">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <StackLayout>
                                    <Label
                                        Text="{Binding RequestUserName}">
                                    </Label>
                                    <Label
                                        Text="{Binding ItemsName}">
                                    </Label>
                                    <Label
                                        Text="{Binding ItemsPrice}">
                                    </Label>
                                    <StackLayout
                                        Orientation="Vertical">
                                        <Button
                                            Text="قبول"
                                            Command="{Binding Source={x:Reference RequestsPage}, Path=BindingContext.RequestAccepted}">
                                        </Button>
                                        <Button
                                            Text="رفض">
                                        </Button>
                                    </StackLayout>
                                </StackLayout>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    

    ViewModel

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows.Input;
    using Xamarin.Forms;
    
    namespace Stack51123113
    {
        public class CustomerTransferRequestsViewModel : INotifyPropertyChanged
        {
    
            public CustomerTransferRequestsViewModel()
            {
                if (GetRequestedItems.CanExecute(null))
                {
                    GetRequestedItems.Execute(null);
                }
                RequestAccepted = new Command(() =>
                {
                    //code goes here
                });
    
            }
            ApiServices _apiServices = new ApiServices();
    
            private ObservableCollection<GetCustomerTransferOrderRespond> _requestedItems;
            private bool _emptyLableVisible;
            private bool _isLoading;
    
            public ObservableCollection<GetCustomerTransferOrderRespond> RequestedItems
            {
                get => _requestedItems;
                set
                {
                    if (Equals(value, _requestedItems)) return;
                    _requestedItems = value;
                    OnPropertyChanged();
                }
            }
    
            public bool EmptyLableVisible
            {
                get => _emptyLableVisible;
    
                set
                {
                    if (Equals(value, _emptyLableVisible)) return;
                    _emptyLableVisible = value;
                    OnPropertyChanged();
                }
    
            }
    
            public bool IsLoading
            {
                get => _isLoading; set
                {
                    if (Equals(value, _isLoading)) return;
                    _isLoading = value;
                    OnPropertyChanged();
                }
            }
    
            public ICommand GetRequestedItems
            {
    
                get
                {
                    return new Command(async () =>
                    {
                        RequestedItems = new ObservableCollection<GetCustomerTransferOrderRespond>(new List<GetCustomerTransferOrderRespond>()
                        {
                            new GetCustomerTransferOrderRespond(),
                            new GetCustomerTransferOrderRespond(),
                        });
                    });
                }
            }
    
            public ICommand RequestAccepted
            {
                get;
                set;
            }
    
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        public class ApiServices
        {
            public ApiServices()
            {
            }
        }
    
        public class GetCustomerTransferOrderRespond
        {
        }
    }