单独的 ListView 模板 xamarin 中按钮的 BindingContext

BindingContext of buttons within a separate ListView template xamarin

所以,我正在 xamarin 上开发应用程序 我尝试包含单独的 DataTemplate。 我的 listView 为 listview 引用了另一个 ContentView 蒙山模板,但按钮不调用视图模型中的 Icommand。

抱歉,我的英语不是很好,但我需要帮助 谢谢。

                  <ListView                     
                        ItemsSource="{Binding ItensOrder}"                                   
                        x:Name="PartListView"                          
                        HasUnevenRows ="True"
                        RowHeight="110"                  
                        IsPullToRefreshEnabled= "{Binding IsNotBusy}"          
                        CachingStrategy="RecycleElement"
                        IsVisible="{Binding IsNotBusy}"    
                        AbsoluteLayout.LayoutFlags="All" 
                        AbsoluteLayout.LayoutBounds="0,0,1,1">
                        <ListView.SeparatorColor>
                            <OnPlatform x:TypeArguments="Color" iOS="{StaticResource ListSeparator}" Android="Transparent"/>
                        </ListView.SeparatorColor>
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <ViewCell StyleId="disclosure">
                                    <local:BasketEquipamentPartCell/>
                                </ViewCell>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>

模板(BasketEquipamentPartCell)代码:

     <AbsoluteLayout HorizontalOptions="StartAndExpand">
                <Grid Padding="16" ColumnSpacing="16">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width=".5*"/>
                        <ColumnDefinition Width=".1*"/>
                        <ColumnDefinition Width=".1*"/>
                        <ColumnDefinition Width=".1*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>

                    <Label VerticalOptions="Center"  Grid.Column="0" Grid.Row="0"  HorizontalOptions="StartAndExpand"  Text="Código Modelo:"/>
                    <Label VerticalOptions="Center" Grid.Column="0" Grid.Row="1"   HorizontalOptions="StartAndExpand" Text="Cópias Por Ciclo:"/>
                    <Label VerticalOptions="Center" Grid.Column="0" Grid.Row="2"   HorizontalOptions="StartAndExpand" Text="Descrição Produto:"/>
                    <Label VerticalOptions="Center" Grid.Column="0" Grid.Row="3"   HorizontalOptions="StartAndExpand" Text="Amount:"/>

                    <Label VerticalOptions="Center" Grid.Column="1" Grid.Row="0"  Grid.ColumnSpan="3" Text="{Binding EquipamentPart.EquipmentModel}"/>
                    <Label VerticalOptions="Center" Grid.Column="1" Grid.Row="1"  Grid.ColumnSpan="3"  Text="{Binding EquipamentPart.LifeCycle}"/>
                    <Label VerticalOptions="Center" Grid.Column="1" Grid.Row="2"  Grid.ColumnSpan="3" Text="{Binding EquipamentPart.Description}"/>
                    <Button Text="+"  Grid.Column="1" Grid.Row="3" 
                                BackgroundColor="DodgerBlue"
                                TextColor="White"
                                WidthRequest="100"
                                 />
                    <Label VerticalOptions="Center" Grid.Column="2" Grid.Row="3" Text="{Binding Amount}" HorizontalOptions="CenterAndExpand"/>
                    <Button Text="-"  Grid.Column="3" Grid.Row="3" 
                                BackgroundColor="DarkGreen"
                                Command="{Binding BindingContext.removeItemOder}"                                  
                                TextColor="White"
                                WidthRequest="100"                                   
                                 />
                    <Button Text="Delete" Grid.ColumnSpan="4" Grid.Column="0" Grid.Row="4" 
                                BackgroundColor="DarkRed"                                    
                                TextColor="White"
                                WidthRequest="100"
                                Command="{Binding Source={x:Reference BasketEquipamentPartCellPage}, Path=BindingContext.removeItemOder}" 
                                CommandParameter="{Binding .}"/>
                </Grid>
            </AbsoluteLayout>`

我在视图模型中的命令

      public class BasketEquipamentPartViewModel : ViewModelBase
{
    public ObservableCollection<OrderItem> ItensOrder { get; set; }

    INavigation navigation;
    private ICommand _removeItemOder, _addItemOder, _deleteOrder;

    private uint _badgeCount;
    public uint BadgeCount
    {
        get { return _badgeCount; }
        set
        {
            _badgeCount = value;
            OnPropertyChanged("BadgeCount");
        }
    }


    public ICommand removeItemOder =>
      _removeItemOder ?? (_removeItemOder = new Command<OrderItem>(async (item) => await removeItemOderCommandAsync(item)));
    public ICommand deleteOrder =>
      _deleteOrder ?? (_deleteOrder = new Command<OrderItem>(async (item) => await deleteOrderCommandAsync(item)));
    public ICommand addItemOder =>
      _addItemOder ?? (_addItemOder = new Command<OrderItem>(async (item) => await addItemOderCommandAsync(item)));


    public BasketEquipamentPartViewModel(INavigation navigation )
    {
        ItensOrder = new ObservableCollection<OrderItem>();            
        this.navigation = navigation;

        CreateMessaging();

    }
    public void CreateMessaging()
    {
        MessagingCenter.Unsubscribe<EquipamentPartOrderViewModel, EquipamentPart>(this, MessageKeys.AddProduct);
        MessagingCenter.Subscribe<EquipamentPartOrderViewModel, EquipamentPart>(this, MessageKeys.AddProduct, async (sender, arg) =>
        {
            BadgeCount++;

            await AddEquipamentPartAsync(arg);
        });
    }
    private async Task AddEquipamentPartAsync(EquipamentPart item)
    {

        if (ItensOrder.Where(x => x.EquipamentPart.Equals(item)).Count() > 0)
        {            
           var index= ItensOrder.IndexOf(ItensOrder.Where(c => c.EquipamentPart == item).FirstOrDefault());
            var i = new OrderItem(ItensOrder[index].EquipamentPart, ItensOrder[index].Amount+1);               

            ItensOrder.RemoveAt(index);
            ItensOrder.Insert(index,i);

        }
        else
        ItensOrder.Add(new OrderItem(item, 1));          
        OnPropertyChanged("ItensOrder");
    }

    private async Task addItemOderCommandAsync(OrderItem item)
    {
        if (ItensOrder.Where(x => x.EquipamentPart.Equals(item.EquipamentPart)).Count() > 0)
        {
            var index = ItensOrder.IndexOf(ItensOrder.Where(c => c.EquipamentPart == item.EquipamentPart).FirstOrDefault());
            var i = new OrderItem(ItensOrder[index].EquipamentPart, ItensOrder[index].Amount + 1);
            ItensOrder.RemoveAt(index);
            ItensOrder.Insert(index, i);
            BadgeCount++;
        }
    }
    private async Task removeItemOderCommandAsync(OrderItem item)
    {
        if (ItensOrder.Where(x => x.EquipamentPart.Equals(item.EquipamentPart)).Count() > 0)
        {
            var index = ItensOrder.IndexOf(ItensOrder.Where(c => c.EquipamentPart == item.EquipamentPart).FirstOrDefault());
            if (ItensOrder[index].Amount > 1)
            {
                var i = new OrderItem(ItensOrder[index].EquipamentPart, ItensOrder[index].Amount - 1);
                ItensOrder.RemoveAt(index);
                ItensOrder.Insert(index, i);
                BadgeCount--;
            }

        }
    }
    private async Task deleteOrderCommandAsync(OrderItem item)
    {
        if (ItensOrder.Where(x => x.EquipamentPart.Equals(item.EquipamentPart)).Count() > 0)
        {
            var index = ItensOrder.IndexOf(ItensOrder.Where(c => c.EquipamentPart == item.EquipamentPart).FirstOrDefault()); 
            ItensOrder.RemoveAt(index);
            BadgeCount-=item.Amount;
        }
    }
}

您的两个视图中的每一个都有自己的 BindingContext。包含 ListView 的视图具有 BasketEquipamentPartViewModel 类型的 BindingContext,这就是 {Binding ItensOrder} 为 ItemsSource 选择正确集合的原因。

然后 Xamarin 将多次使用 BasketEquipamentPartCell,为集合中的每个元素使用一次,为每个 OrderItem 设置 BindingContext。因此,BasketEquipamentPartCell 无法直接引用集合的 BindingContext。在 Button 上计算 Command="{Binding BindingContext.removeItemOder}" 时,Xamarin.Forms 将查看 OrderItem 的属性以查找 removeItemOder,但不会找到它。当 Xamarin.Forms 找不到 属性 时,它会默默地忽略它,因此您的应用程序的其余部分可以正常工作。

要解决此问题,您需要在可以绑定到的 OrderItem 上定义命令 属性。

如何实现的草图

解决此问题的一种方法是在 BasketEquipamentPartViewModel 上添加一个方法,该方法使用 MessagingCenter(您已经将其用于其他用途)侦听移除项目的请求:

public void CreateMessaging()
{
    MessagingCenter.Subscribe<OrderItem>(this, "RemoveOrderItem", RemoveItem);
    // the rest of CreateMessaging you already have
}

private void RemoveItem(OrderItem itemToRemove)
{
    // do the stuff you're already doing in removeItemOder
}

请注意,您似乎没有在 removeItemOder 中执行任何异步工作,因此您应该删除异步并使其 return 无效。

然后在 OrderItem class 中创建如下命令:

private ICommand _removeItemOrder;
public ICommand removeItemOder => _removeItemOrder ??
       (_removeItemOrder = new Command<OrderItem>(item => MessagingCenter.Send(this, "RemoveOrderItem"));

然后 {Binding BindingContext.removeItemOder}(或简单的 {Binding removeItemOder} - BindingContext 在这里是多余的)将成功找到要调用的命令。