从GetView()方法中的同一ListView行的列表中返回重复值的最佳方法是什么?

时间:2022-09-16 14:30:36

I have some data in a list that shows for example the Item Number, Line Number, Quantity, and Pack Size of an order. The problem is that some lines on the order will have the same item number but different quantities, pack sizes or both. For example :

我在列表中有一些数据,例如显示订单的项目编号,行号,数量和包大小。问题是订单上的某些行将具有相同的商品编号,但数量,包装尺寸或两者都不同。例如 :

Order#  Line#   Item#   Qty    Pack Size
100      1      12345   640     (10@64)
100      1      12345   128     (1@128)
100      2      23124    48     (1@48)
100      3      53425    80     (1@80)

Shown above for item 12345 they have ordered a total of 768 pieces but for 640 of those pieces they would like to receive 10 packs containing 64 pieces each and they would like 128 of the pieces in just one pack. When the ListView is created naturally it will create 4 rows, one row for each of the rows in the list. I would like it to only show 3 rows one for each Item# and if there are duplicate items it should add the quantities and combine the pack sizes into one row. I have tried doing something like this trying to force it to do what i wanted but it obviously does not work that well. I am fairly new to Android and ListViews so I am hoping that there is a better way to accomplish this. Can anyone point me in the right direction?

如上所示,对于12345项目,他们总共订购了768件,但是对于这些件中的640件,他们希望收到10件装,每件64件,他们希望只有一件装有128件。自然创建ListView时,它将为列表中的每一行创建4行,一行。我希望每个Item#只显示3行,如果有重复项,则应添加数量并将包大小合并为一行。我试过做这样的事情试图强迫它做我想要的但是它显然效果不好。我对Android和ListView相当新,所以我希望有更好的方法来实现这一点。谁能指出我正确的方向?

    public class LoadInfoViewAdapter : BaseAdapter<Items>
{
    private List<Items> lItems;
    private Context gContext;
    private string gLoadnStop;
    private string gPacks;
    private decimal gtotal;
    int total;

    public LoadInfoViewAdapter(Context context, List<Items> loadinfo,  string LoadnStop)
    {
        lItems = loadinfo;
        gContext = context;
        gLoadnStop = LoadnStop;

    }

    public override int Count
    {
        get { return lItems.Count; }
    }
    public override long GetItemId(int position)
    {
        return position;
    }
    public override Items this[int position]
    {
        get { return lItems[position]; }
    }
    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View row = convertView;
        if (row == null)
        {
            row = LayoutInflater.From(gContext).Inflate(Resource.Layout.LoadInfoItems_Row, null);
        }
        //If the item at the current position is the same as the item in the next position add the qty and combine the packs
        if (lItems[position].ItemNo == lItems[position + 1].ItemNo)
        {
            string itemno = lItems[position].ItemNo;
            int count = 0;
            row.FindViewById<TextView>(Resource.Id.txtItemNo).Text = lItems[position].ItemNo.Trim();
            row.FindViewById<TextView>(Resource.Id.txtLineNo).Text = lItems[position].LineNum.Trim();
            foreach (var item in lItems.Where(r => r.ItemNo == itemno))
            {
                if (count == 0)
                {
                    gPacks = lItems[position].Pack.ToString().Trim();
                    gtotal = lItems[position].Qty;
                }
                else
                {
                    gPacks = lItems[position + 1].Pack.ToString().Trim() + ", " + gPacks;
                    gtotal = lItems[position + 1].Qty + gtotal;
                }
                count = +1;
            }
            row.FindViewById<TextView>(Resource.Id.txtQuantity).Text = gtotal + " (" + gPacks + ") ";
            gtotal = 0;
        }
        //check to see if the current item is was the same as the previous item added.  If so I dont want to create a row for that item.
        else if (lItems[position].ItemNo == lItems[position - 1].ItemNo)
        {
            //Not too sure what would be the best code to go here
        }
        //if it has no duplicate create the row like normal
        else
        {
            row.FindViewById<TextView>(Resource.Id.txtItemNo).Text = lItems[position].ItemNo.Trim();
            row.FindViewById<TextView>(Resource.Id.txtLineNo).Text = lItems[position].LineNum.Trim();
            row.FindViewById<TextView>(Resource.Id.txtQuantity).Text = lItems[position].Qty.ToString().Trim() + lItems[position].Pack.ToString().Trim();
        }
        return row;
    }

I would like it to return something like this :

我希望它返回这样的东西:

12345  1   768((10@64),(1@128))
23124  2   48(1@48)
53425  3   80(1@80)

For whatever reason it will do what i was hoping for the duplicate item numbers but it sometimes duplicates a different item in the list like:

无论出于何种原因,它都会做我希望重复的项目编号,但它有时会复制列表中的不同项目,如:

12345  1   768((10@64),(1@128))
23124  2   48(1@48)
53425  3   80(1@80)
23124  2   48(1@48)

Anyone got any suggestions?

有人有什么建议吗?

1 个解决方案

#1


0  

Your fundamental issue is that the Items indexer is stating that you have 4 items available, but your desired result is 3 items.

您的根本问题是Items索引器声明您有4个项目可用,但您想要的结果是3个项目。

This isn't really a task that you should be solving in your BaseAdapter. You should be processing the list in advance and reducing to your target 3 items BEFORE passing it into your base adapter.

这不是您应该在BaseAdapter中解决的任务。您应该提前处理列表,并在将其传递到基础适配器之前将其减少到目标3项。

Also, you should try and avoid using FindViewFromId in GetView, unless the convertView is null. In order to do this, you can pack the previously identified Views into the Tag property: that's what it's for, see https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

此外,您应该尽量避免在GetView中使用FindViewFromId,除非convertView为null。为此,您可以将之前标识的视图打包到Tag属性中:这就是它的用途,请参阅https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

If you really want to do it all in your base adapter, then convert the items in the constructor, something like this:

如果你真的想在基础适配器中完成所有操作,那么转换构造函数中的项目,如下所示:

public class LoadInfoViewAdapter : BaseAdapter<Items>
{
    private List<CondensedItems> cItems;
    private Context gContext;

    public LoadInfoViewAdapter(Context context, List<Items> loadinfo,  string LoadnStop)
    {        
        gContext = context;
        gLoadnStop = LoadnStop;

        // Get all of the unique item numbers.
        var uniqueItemNos = loadInfo.Select(x => x.ItemNo).Distinct();

        cItems = new List<CondensedItem>();

        foreach(string uniqueItem in uniqueItemNos)
        {
            // Gets all of the items with the target itemNo.  If you want to avoid merging them all, you need to do some work checking for sequential indexes or something similar.
            var matchingItems = loadInfo.Select(x => x.ItemNo == uniqueItem).ToList();
            var lineNo = matchingItems[0].LineNo;
            var qty = matchingItems.Sum(x => x.Qty).ToString();

            StringBuilder packsSB = new StringBuilder();

            foreach(var item in matchingItems)
            {
                packs.Append(item.Pack + ",");
            }

            string packs = packsSB.ToString().Trim(',');

            cItems.Add(
                new CondensedItem 
                {
                    ItemNo = uniqueItem,
                    LineNo = lineNo,
                    Packs = $"{qty}({packs})"
                });  
        }       
    }

    public override int Count
    {
        get { return cItems.Count; }
    }
    public override long GetItemId(int position)
    {
        return position;
    }
    public override Items this[int position]
    {
        get { return cItems[position]; }
    }
    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View row = convertView;
        CondensedViewHolder viewHolder;

        if (row == null)
        {
            row = LayoutInflater.From(gContext).Inflate(Resource.Layout.LoadInfoItems_Row, null);

            viewHolder = new CondensedViewHolder 
            {
                ItemView = row.FindViewById<TextView>(Resource.Id.txtItemNo),
                LineView = row.FindViewById<TextView>(Resource.Id.txtLineNo),
                PacksView = row.FindViewById<TextView>(Resource.Id.txtQuantity)
            }

            row.Tag = viewHolder;
        }
        else
        {
            viewHolder = row.Tag as CondensedViewHolder;
        }

        viewHolder.ItemView.Text = cItems[position].ItemNo;
        viewHolder.LineView.Text = cItems[position].LineNo;
        viewHolder.PacksView.Text = cItems[position].Packs;

        return row;
    }

    private class CondensedItem
    {
        string ItemNo { get; set; }
        string LineNo { get; set; }
        string Packs { get; set; }
    }   

    private class CondensedViewHolder : Java.Lang.Object
    {
        public TextView ItemView { get; set; }
        public TextView LineView { get; set; }
        public TextView PacksView { get; set; }
    }
}

#1


0  

Your fundamental issue is that the Items indexer is stating that you have 4 items available, but your desired result is 3 items.

您的根本问题是Items索引器声明您有4个项目可用,但您想要的结果是3个项目。

This isn't really a task that you should be solving in your BaseAdapter. You should be processing the list in advance and reducing to your target 3 items BEFORE passing it into your base adapter.

这不是您应该在BaseAdapter中解决的任务。您应该提前处理列表,并在将其传递到基础适配器之前将其减少到目标3项。

Also, you should try and avoid using FindViewFromId in GetView, unless the convertView is null. In order to do this, you can pack the previously identified Views into the Tag property: that's what it's for, see https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

此外,您应该尽量避免在GetView中使用FindViewFromId,除非convertView为null。为此,您可以将之前标识的视图打包到Tag属性中:这就是它的用途,请参阅https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

If you really want to do it all in your base adapter, then convert the items in the constructor, something like this:

如果你真的想在基础适配器中完成所有操作,那么转换构造函数中的项目,如下所示:

public class LoadInfoViewAdapter : BaseAdapter<Items>
{
    private List<CondensedItems> cItems;
    private Context gContext;

    public LoadInfoViewAdapter(Context context, List<Items> loadinfo,  string LoadnStop)
    {        
        gContext = context;
        gLoadnStop = LoadnStop;

        // Get all of the unique item numbers.
        var uniqueItemNos = loadInfo.Select(x => x.ItemNo).Distinct();

        cItems = new List<CondensedItem>();

        foreach(string uniqueItem in uniqueItemNos)
        {
            // Gets all of the items with the target itemNo.  If you want to avoid merging them all, you need to do some work checking for sequential indexes or something similar.
            var matchingItems = loadInfo.Select(x => x.ItemNo == uniqueItem).ToList();
            var lineNo = matchingItems[0].LineNo;
            var qty = matchingItems.Sum(x => x.Qty).ToString();

            StringBuilder packsSB = new StringBuilder();

            foreach(var item in matchingItems)
            {
                packs.Append(item.Pack + ",");
            }

            string packs = packsSB.ToString().Trim(',');

            cItems.Add(
                new CondensedItem 
                {
                    ItemNo = uniqueItem,
                    LineNo = lineNo,
                    Packs = $"{qty}({packs})"
                });  
        }       
    }

    public override int Count
    {
        get { return cItems.Count; }
    }
    public override long GetItemId(int position)
    {
        return position;
    }
    public override Items this[int position]
    {
        get { return cItems[position]; }
    }
    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View row = convertView;
        CondensedViewHolder viewHolder;

        if (row == null)
        {
            row = LayoutInflater.From(gContext).Inflate(Resource.Layout.LoadInfoItems_Row, null);

            viewHolder = new CondensedViewHolder 
            {
                ItemView = row.FindViewById<TextView>(Resource.Id.txtItemNo),
                LineView = row.FindViewById<TextView>(Resource.Id.txtLineNo),
                PacksView = row.FindViewById<TextView>(Resource.Id.txtQuantity)
            }

            row.Tag = viewHolder;
        }
        else
        {
            viewHolder = row.Tag as CondensedViewHolder;
        }

        viewHolder.ItemView.Text = cItems[position].ItemNo;
        viewHolder.LineView.Text = cItems[position].LineNo;
        viewHolder.PacksView.Text = cItems[position].Packs;

        return row;
    }

    private class CondensedItem
    {
        string ItemNo { get; set; }
        string LineNo { get; set; }
        string Packs { get; set; }
    }   

    private class CondensedViewHolder : Java.Lang.Object
    {
        public TextView ItemView { get; set; }
        public TextView LineView { get; set; }
        public TextView PacksView { get; set; }
    }
}