单独的 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 在这里是多余的)将成功找到要调用的命令。
所以,我正在 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 在这里是多余的)将成功找到要调用的命令。