【问题标题】:Binding button to command inside listview dataTemplate将按钮绑定到列表视图数据模板中的命令
【发布时间】:2018-07-01 12:03:13
【问题描述】:

我遇到了这个解决方案,它应该绑定到根页面而不是对我不起作用的列表视图(我正在尝试在列表视图内按下按钮并传递列表视图项目 ID 时执行命令)现在( Path=BindingContext.RequestAccepted) 无法解析对象类型数据上下文中的属性“RequestAccepted”。

<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>

视图模型

 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));
    }
}

【问题讨论】:

  • 看起来应该可以了。试试“..Source={x:Reference Name=RequestsPage}..” Name= 部分是我看到的与过去的唯一区别。需要设置一个测试项目来验证。
  • 不幸地尝试过......同样的事情。

标签: listview xamarin xamarin.forms binding icommand


【解决方案1】:

我认为您需要做的是定义 ICommand 属性并使用 Command 进行分配,

ViewModel 中的类似内容。

public ICommand RequestAccepted
    {
        get;
        set;
    }

在构造函数中,您可以使用这样的命令分配属性,

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

    }

.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"
    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>

视图模型

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

【讨论】:

  • 这并没有什么不同..仍然无法直接从xaml页面执行命令。
  • 我的问题是我不能绑定到根目录(viewmodel)而不是在列表视图中,因为源是 RequestedItems 我只能绑定到这个列表道具,而不是像命令一样绑定到视图模型道具的其余部分,所以当我写 Command="{Binding Source={x:Reference RequestsPage}, Path=BindingContext.RequestAccepted}"> ........ 我得到一个(无法解析属性“RequestAccepted”)
  • 是的,我只使用您的代码创建了测试环境,我将发布 .XAML 和 viewmode 文件供您参考(虽然它是演示)
  • 我已经用这两个文件编辑了我的答案,希望对您有所帮助
  • 非常感谢 .. 事实证明 .. 问题出在 Resharper .. 出于某种原因,它一直存在(无法解析属性).. 但是当我尝试运行代码时直接它的工作。
【解决方案2】:

在 ListView 中,使用“command parameter”和“clicked”来分别获取每个按钮的命令。

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
 }

希望这会有所帮助。

【讨论】:

  • 嗯,这行得通,但我想知道是否有办法不写页面后面的代码..(只有 xaml 和 viewmodel)。
  • 尝试在 'command' 参数而不是 'Clicked' 参数中绑定函数。
  • 在列表视图中,我只能绑定到 ItemsSource 在我的情况下(RequestedItems)列表..现在的问题是我想在我的视图模型中绑定一个命令而不是列表..所以我试图绑定到 rootpage这是视图模型,但是当我写 Command="{Binding Source={x:Reference RequestsPage}, Path=BindingContext.RequestAccepted}"> ........ 我得到一个(无法解析属性"请求接受")
【解决方案3】:

我用来为列表中的每个项目创建一个 ViewModel。如果我已经有一个模型,我会在 ViewModel 中使用它,通常是在一个名为 Item 的属性中。所以在绑定中我会写 Item.RequestUserName 例如。但这使我可以向 ViewModel 添加命令并绑定它们。

【讨论】:

  • 每个项目的视图模型?! ..你能举个例子吗?
猜你喜欢
  • 2018-04-19
  • 1970-01-01
  • 2010-12-27
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 2016-01-14
  • 2013-03-25
  • 1970-01-01
相关资源
最近更新 更多