c# - Enlace de comando de botón de formularios de Xamarin dentro de un ListView
xaml xamarin.forms (4)
Aquí hay otra cosa que puede sorprenderte. El enlace con el comando nunca ocurrirá, si accidentalmente define su ICommand en el ViewModel como una propiedad privada.
Tengo el siguiente problema, en mi opinión tengo una vista de lista. En esta vista de lista me gustaría tener dos botones. Uno para editar el elemento, otro para borrarlo.
Aquí está mi vista de lista en XAML
<ListView Grid.Row="1" x:Name="ArbeitsEinträgeList" ItemsSource="{Binding EintragList}" SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Titel}" TextColor="{Binding Fehlerhaft, Converter={StaticResource EintragartConverter}}"></Label>
<Label Grid.Column="1" Text="{Binding Beginn}" TextColor="{Binding BeginnManuell, Converter={StaticResource EintragartConverter}}"></Label>
<Label Grid.Column="2" Text="{Binding Ende}" TextColor="{Binding EndeManuell, Converter={StaticResource EintragartConverter}}"></Label>
<Button Grid.Column="3" Command="{Binding EditEintragCommand}" Text="" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
<Button Grid.Column="4" Command="{Binding DeleteEintragCommand}" Text="" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
En mi ViewModel es todo lo que necesito, he probado los comandos con un botón que no está en la vista de lista y funciona perfectamente.
Si muevo el cursor sobre el enlace, aparece el mensaje "No se puede resolver el símbolo ''...''"
Ene,
Dado que ha utilizado una vista de lista y sus comandos están dentro de DataTemplate, el enlace se adjunta al contexto de enlace de cada modelo individual en ItemSource.
Una forma de evitar esto es hacer lo siguiente:
<ListView Grid.Row="1" x:Name="ArbeitsEinträgeList" ItemsSource="{Binding EintragList}" SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid x:Name="Item">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Titel}" TextColor="{Binding Fehlerhaft, Converter={StaticResource EintragartConverter}}"></Label>
<Label Grid.Column="1" Text="{Binding Beginn}" TextColor="{Binding BeginnManuell, Converter={StaticResource EintragartConverter}}"></Label>
<Label Grid.Column="2" Text="{Binding Ende}" TextColor="{Binding EndeManuell, Converter={StaticResource EintragartConverter}}"></Label>
<Button Grid.Column="3" BindingContext="{Binding Source={x:Reference ArbeitsEinträgeList}, Path=BindingContext}" Command="{Binding EditEintragCommand}" CommandParameter="{Binding Source={x:Reference Item}, Path=BindingContext}" Text="" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
<Button Grid.Column="4" BindingContext="{Binding Source={x:Reference ArbeitsEinträgeList}, Path=BindingContext}" Command="{Binding DeleteEintragCommand}" CommandParameter="{Binding Source={x:Reference Item}, Path=BindingContext}" Text="" FontFamily="../Ressources/fontawesome.ttf#FontAwesome"></Button>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Así que configura la fuente de enlace para que haga referencia al contexto de enlace de la vista de lista (es decir, su modelo de vista o "ArbeitsEinträgeList". También puede configurar el parámetro de comando para que sea el contexto de enlace de cada elemento individual. Como puede ver, tengo x: Nombre = "Elemento" en la cuadrícula y CommandParameter = "{Fuente de enlace = {x: Elemento de referencia}, Ruta = BindingContext}".
Simplemente, la declaración de comandos como este le permite definir un comando genérico en su modelo de vista y cuando el comando se ejecuta con el parámetro comando como el contexto de enlace del elemento individual.
public ICommand DeleteEintragCommand
{
get
{
return new Command((e) =>
{
var item = (e as MyModelObject);
// delete logic on item
});
}
}
Esto se debe a que se enlaza a un elemento de su propiedad EintragList
(por eso es que su enlace a las propiedades de texto como Beginn
y Ende
funciona). Y el enlace de comando intenta alcanzar un comando en un solo elemento de su lista y no desde su modelo de vista.
Opción 1: establece el comando en su clase de elemento y maneja el toque allí.
Opción 2: indique a su enlace que la fuente debe ser su página (y no el único elemento):
Command="{Binding BindingContext.EditEintragCommand, Source={x:Reference Name=MyPageName}}"
Solo asegúrese de que el nombre del elemento raíz de su página esté establecido x:Name="MyPageName"
Para saber qué elemento activa el comando, puede establecer la propiedad CommandParameter, que también se envía al comando como un objeto:
CommandParameter="{Binding .}"
Adicional: cuando está utilizando plantillas externas para mostrar los elementos de su lista, puede intentar algo que describí en otra respuesta (el mismo principio).
Si desea enlazar un clic en el botón, también puede intentar usar el evento clic en el atributo Button. Aquí está mi código y funcionó para mí.
<ListView x:Name="lst1" RowHeight="80">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Padding="8,0,8,0">
<Label Text="{Binding Fname}" TextColor="#000" FontSize="14" LineBreakMode="TailTruncation" />
<Label Text="{Binding Mobile}" TextColor="#000" LineBreakMode="TailTruncation" />
<Button Text="Remove" Clicked="Delete" CommandParameter="{Binding ID}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
y el lado del código simplemente puede implementar el método de eliminación con un argumento como
public void Delete(Object Sender, EventArgs args)
{
Button button = (Button)Sender;
string ID = button.CommandParameter.ToString();
// Do your Stuff.....
}