简体   繁体   中英

Xamarin.forms: How to get Object value from a Listview

I am placing a stepper inside a Listview. I would like to know which Item the Stepper belong to when I change it. Here is the Listview. I would like to know, when I modify the stepper's value, which EAN is part of the same ViewCell.

        <ListView x:Name="ItemsListView"
            ItemsSource="{Binding Items}"
            VerticalOptions="FillAndExpand"
            HasUnevenRows="true"
            RefreshCommand="{Binding LoadItemsCommand}"
            IsPullToRefreshEnabled="true"
            IsRefreshing="{Binding IsBusy, Mode=OneWay}"
            CachingStrategy="RecycleElement"
            ItemTapped="OnItemSelected"
              >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Padding="10" Orientation="Vertical" HorizontalOptions="FillAndExpand">
                            <Label Text="{Binding Name}" LineBreakMode="WordWrap"  FontSize="16" HorizontalOptions="FillAndExpand"  />
                            <Label Text="{Binding QuantityExpectedDisplay}" LineBreakMode="WordWrap"  FontSize="10" HorizontalOptions="FillAndExpand"  />
                            <Label Text="{Binding EAN}" LineBreakMode="WordWrap"  FontSize="10" HorizontalOptions="FillAndExpand"  />
                            <Stepper Value="{Binding QuantityDefect}" Minimum="0" Maximum="{Binding Quantity}" HorizontalOptions="FillAndExpand" ValueChanged="Stepper_ValueChanged" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

So that I can use that ean later to find the corresponding line. (In the example, I would like to find the ListItem, or at least its EAN in test, rather than putting a new one)

    private void Stepper_ValueChanged(object sender, ValueChangedEventArgs e)
    {
        ListItem test = new ListItem();//Here I'd like the ViewCell Values
        var line = viewModel.lines.Find(l => l.Ean == test.EAN);
        line.QuantityOpen = (int)e.NewValue;
    }

Thank you and have a nice day

We generally don't recommend using this method,you can implement INotifyPropertyChanged for your the item of Items .

Suppose the item model is Item.cs , you can implement INotifyPropertyChanged as follows:

public class Item: INotifyPropertyChanged
{
    public string Name { get; set; }
    public string QuantityExpectedDisplay{ get; set; }
    public string EAN{ get; set; }

    //public int  QuantityDefect { get; set; }

    int _quantityDefect;
    public int QuantityDefect
    {
        set { SetProperty(ref _quantityDefect, value); }

        get { return _quantityDefect; }
    }

    public int Quantity { get; set; }

    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

And in YourPage.xaml ,we can do like this:

    <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Padding="10" Orientation="Vertical" HorizontalOptions="FillAndExpand">
                        <Label Text="{Binding Name}" LineBreakMode="WordWrap"  FontSize="16" HorizontalOptions="FillAndExpand"  />
                        <Label Text="{Binding QuantityExpectedDisplay}" LineBreakMode="WordWrap"  FontSize="10" HorizontalOptions="FillAndExpand"  />
                        <Label Text="{Binding EAN}" LineBreakMode="WordWrap"  FontSize="10" HorizontalOptions="FillAndExpand"  />
                        <Stepper Value="{Binding QuantityDefect}" Minimum="0" Maximum="10" Increment="1" HorizontalOptions="FillAndExpand"  />
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>

Note:

Once we change the stepper's value, the value of QuantityDefect will change accordingly.

Update

How can I find more information about this type of binding? How is it called, so I can find out how it works for later?

Yes, if we implement INotifyPropertyChanged for Item and change the value, it also change the value of the ItemsSource of current listview.

For example,, suppose the view model of current page is MyViewModel.cs :

    public class MyViewModel
{
    public ObservableCollection<Item> items { get; set; }
    public MyViewModel() {
        items = new ObservableCollection<Item>();

        items.Add(new Item { Name = "Tomato", Quantity = 100, QuantityDefect = 10 });
        items.Add(new Item { Name = "Romaine Lettuce",  Quantity = 100, QuantityDefect = 10 });
        items.Add(new Item { Name = "Zucchini", Quantity = 100, QuantityDefect = 10 });

    }
}

Then we can also get the modified ItemsSource as follows(I added a Button to print the data):

public partial class MainViewXaml : ContentPage
{

    MyViewModel viewModel;
    public MainViewXaml ()
    {
        InitializeComponent();

        viewModel = new MyViewModel();
        BindingContext = viewModel;
    }

    private void Stepper_ValueChanged(object sender, ValueChangedEventArgs e)
    {

    }
    // we can get the items here
    private void Button_Clicked(object sender, System.EventArgs e)
    {
        foreach (Item item in viewModel.items) {
            System.Diagnostics.Debug.WriteLine(" name : " + item.Name + "<-----> QuantityDefect = " + item.QuantityDefect);
        }
    }
}

First, see Jessie's answer for the basics of Data Binding to a list of items.

Or see example described in ListView Data Sources .


In addition, we need a way to tell viewmodel what item has changed.

MessagingCenter can do this.

MyViewModel.cs:

public MyViewModel()
{
    MessagingCenter.Subscribe<MyItem>(this, "changed", Item_Changed);
}

public ObservableCollection<MyItem> Items { get; set; }

private void Item_Changed(MyItem item)
{
    var index = Items.IndexOf(item);
    // Make sure it is mine.
    if (index >= 0)
    {
        // ...
    }
}

MyItem.cs:

int _quantityDefect;
public int QuantityDefect
{
    get => _quantityDefect;
    set
    {
        SetProperty(ref _quantityDefect, value);
        Xamarin.Forms.MessagingCenter.Send<MyItem>(this, "changed");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM