1
votes

I'm listing records from my ListItem tables in my SQLite database in a ListView, and each record is its own button, which leads to an EditItem method. All I want to do in this method is set the boolean Large attribute for the ListItem to false, but I'm having trouble getting the corresponding ListItem as a variable.

With my current code, the error I'm getting is:

Error CS0266 Cannot implicitly convert type 'object' to 'Myapp.Models.ListItem'. An explicit conversion exists (are you missing a cast?)

What's the correct way to get and update the selected record in my code behind?

UPDATE

I tried using a Command with my button, and now I don't get any errors, but the EditItem method isn't even called. I now know how to pass parameters with the Command property, but I'm not sure how to call a method with it. I know how to call a method with the Clicked property, but I don't know how to pass parameters with it.

Xaml:

    <ListView>
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout>
                        <Button Text="{Binding Name}" Command="EditItem" CommandParameters="{Binding}" VerticalOptions="Start"/>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

C# Code Behind:

    public async void EditItem(object sender, EventArgs e)
    {
        ListItem item = (ItemList)sender as ItemList;
        item.Large = false;
        ...
    }

I'm using the sqlite-net-pcl Nuget package in a Xamarin.forms app.


1

1 Answers

4
votes

Try ListItem item = (ListItem)e.SelectedItem;.

Right now you are trying to assign a generic object to a ListItem type, you should tell it what type it is.

You probably want some safeguards in there to make sure it is actually a ListItem object. I.e.:

var selectedListItem = e.SelectedItem as ListItem;

if (selectedListItem == null)
{
    // TODO inform user or something
    return;
}

In accordance with what you are looking for according to your comments, I will elaborate a bit more. For what you want to do, its best to use the Command and CommandParameter on the Button. There is one thing to note here. For the Command on the Button, you probably want to execute code from your view model. But the scope within one ViewCell is that of a ListItem. To make sure the Command is being searched for in the right place, give the Page a name, i.e. like this: <ContentPage xmlns="..." x:Name="MyPage">.

Now from the Button go like this: <Button Text="{Binding Name}" Command="{Binding Source={x:Reference MyPage}, Path=BindingContext.EditItem}" CommandParameters="{Binding .}" VerticalOptions="Start"/>. This tells the button to set the source of the binding for the Command to the page with name MyPage. The actual source of the binding is then set to the BindingContext.EditItem property. If you're not using a separate view model but just use the code-behind, omit the BindingContext. part.

The last thing you need to do is add the actual Command. In your view model (or in the code-behind) add a property: public Command EditItem { get; set; } and add the executable code in the constructor or how else you would like to initialize it:

public MyPage()
{
    EditItem = new Command((parameter) => {
        ListItem item = (ItemList)parameter as ItemList;

        if (item == null)
            return; // TODO error handling

        item.Large = false;
    });
}

Because of the BindingParameter on your Button, which is set to ., meaning that it is bound to the actual object that is behind that ViewCell, you will retrieve the ListItem as the parameter.

You probably want to move the Command code into a separate method for readability. Hope this makes sense.