0
votes

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));
    }
}
3
That looks like it should work. Try "..Source={x:Reference Name=RequestsPage}.." The Name= part is the only difference I see with how I've done it in the past. Would need to setup a test project to verify.Ben Reierson
Tried ... same thing sadly .Khalid Hex

3 Answers

2
votes

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
    {
    }
}
0
votes

Inside a ListView, use the 'command parameter' along with 'clicked' to get the command for each button individually.

xaml

 <Button CommandParameter="{Binding ItemID}" Clicked="ItemClicked" />

xaml.cs

 async void ItemClicked(object sender, System.EventArgs e)
 {
     var Button = (Button)sender;
     String Value = Button.CommandParameter.ToString(); // This gives the Item ID
 }

Hope this helps.

0
votes

I use to create an ViewModel for each item in a list. If I already have a model I use that inside the ViewModel, often in a property called Item. So in the binding I will write Item.RequestUserName for example. But this makes it possible for me to add commands to the ViewModel and bind against them.