Android Xamarin c# 替换 Fragment 后无法更新视图

问题描述 投票:0回答:1

我有一个正在处理物品“制作”的片段,它显示一个“制作台”、物品成本清单和库存。 在片段的第一次初始化时,制作台工作正常,但在我将其替换回来和第四次之后,当我制作时(单击制作按钮)它不会更新。

这是一个例子: Example Video

我尝试用 Handler.Post 包装一些函数,但没有成功。

片段:

using Android.Graphics;
using Android.OS;
using Android.Views;
using Android.Widget;
using AndroidX.Fragment.App;
using MineClick.Crafting.Bench;
using MineClick.Crafting.Bench.CostList;
using MineClick.EventSystem;
using MineClick.EventSystem.EventArguments;
using MineClick.Materials;
using MineClick.Navigation;
using MineClick.Pickaxes;
using MineClick.Player;
using MineClick.Utility;
using static MineClick.EventSystem.EventManager;
using static MineClick.InventoryView;

namespace MineClick.Crafting
{
    internal class CraftFragment : Fragment
    {

        CraftAdapter CraftAdapter { get; set; }

        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);



        }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
           
            View view = inflater.Inflate(Resource.Layout.crafting_activity, container, false);
            LinearLayout wrraper = view.FindViewById<LinearLayout>(Resource.Id.crafting_wrraper);
            LinearLayout inventoryWrraper = view.FindViewById<LinearLayout>(Resource.Id.inventory_wrraper);

            LinearLayout costListWrraper = view.FindViewById<LinearLayout>(Resource.Id.cost_list_wrraper);
           
            CraftingBench bench = new CraftingBench(Context);
            wrraper.AddView(bench);

            InventoryView inventoryDisplay = new InventoryView(Context, PlayerApplication.Instance.Player.PlayerInventory);
            inventoryWrraper.AddView(inventoryDisplay);
            CostListView costList = new CostListView(Context);
            costListWrraper.AddView(costList);
            CraftAdapter = new CraftAdapter(inventoryDisplay, bench,costList);
            return view;
        }

    }
}

工艺适配器:

using Android.Widget;
using MineClick.Crafting.Bench.CostList;
using MineClick.Crafting.Recipes.Handlers;
using MineClick.EventSystem;
using MineClick.Materials;
using MineClick.Player;
using static MineClick.EventSystem.EventManager;
using static MineClick.InventoryView;

namespace MineClick.Crafting
{
    internal class CraftAdapter
    {

        InventoryView InvView;
        RecipeAdapter BenchAdapter;
        public CraftAdapter(InventoryView invView, CraftingBench bench, CostListView costList)
        {
            InvView = invView;
            BenchAdapter = new RecipeAdapter(bench,costList);
            Initialize();
        }

        private void Initialize()
        {
            InvView.OnClickActions = OnInvClick;
            EventManager.BindListener(Events.ITEM_CRAFTED, (sender, args) => OnCraft(args.CraftedItem));
        }

        public void OnInvClick(InventoryClickEvent e)
        {
            if (e.ClickedItem.DisplayedItem == null)
                return;
            Item itemToAdd = ItemRegistry.GetItemById(e.ClickedItem.DisplayedItem.GetItem().Id);

            bool add = BenchAdapter.OnAttemptAddItem(itemToAdd.Clone());

            // Do something if add failed (toast or something)
            if(!add)
                Toast.MakeText(e.ClickedItem.Context, "Cannot Add Item To Bench",ToastLength.Long);
            
        }

        public void OnCraft(Item item)
        {
            PlayerApplication.Instance.Player.PlayerInventory.Add(item);
            BenchAdapter.Reset();
            InvView.Update();
            
        }
    }
}

配方适配器:

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using MineClick.Crafting.Bench;
using MineClick.Crafting.Bench.CostList;
using MineClick.EventSystem;
using MineClick.EventSystem.EventArguments;
using MineClick.Materials;
using MineClick.Player;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static MineClick.EventSystem.EventManager;

namespace MineClick.Crafting.Recipes.Handlers
{
    internal class RecipeAdapter
    {
        public CraftingBench Bench { get; set; }
        public RecipeManager Manager { get; set; }

        public CostListView CostList;
        public RecipeAdapter(CraftingBench bench, CostListView costList,Item defaultMainItem,Item[] defaultExtras)
        {
            Manager = new RecipeManager(defaultMainItem,defaultExtras);
            Bench = bench;
            CostList = costList;
            CostList.CButton.Click += (sender, args) => Craft();
            Update();
        }

        public RecipeAdapter(CraftingBench bench, CostListView costList)
        {
            Manager = new RecipeManager();
            Bench = bench;
            CostList = costList;
            CostList.CButton.Click += (sender, args) => Craft();
            Update();
        }

        public bool OnAttemptAddItem(Item item)
        {
            if (Manager.AttemptAddItem(item))
                Update();
            else return false;

            return true;
        }

        public void Update()
        {
            Bench.UpdateBench(Manager.MainItem, Manager.Extras, Manager.GetResultDisplay(Bench.Context));

            UpdateCostList();
        }

        private void UpdateCostList()
        {
            Dictionary<Item, bool> costList = new Dictionary<Item, bool>();
            Inventory inventory = PlayerApplication.Instance.Player.PlayerInventory;
            if(Manager.CalculateCost() != null)
            Manager.CalculateCost().ForEach(item =>
            {
                bool valid = true;
                if (!inventory.Contains(item.Id))
                    valid = false;
                else if (item is CountableItem)
                    valid = ((CountableItem)item).Amount <= ((CountableItem)inventory.Get(item.Id)).Amount;
                costList.Add(item, valid);
            });

            CostList.Recycler.Adapter.SetItems(costList);
            CostList.CButton.Valid = costList.All(entry => entry.Value);
            CostList.CButton.Visibility = costList.Count == 0 ? ViewStates.Invisible : ViewStates.Visible;
            
        }


        private void Craft()
        {
            Item crafted = Manager.CalculateResult();
            if (CostList.CButton.Valid)
                EventManager.InvokeEvent(Events.ITEM_CRAFTED, new EA_ITEM_CRAFTED(crafted));
        }

        public void Reset()
        {
            Manager.Reset();
            Update();
        }
    }
}

菜谱经理:

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using MineClick.Materials;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MineClick.Crafting.Recipes.Handlers
{
    internal class RecipeManager
    {
        public static readonly int EXTRAS_AMOUNT = 6;
        public Item MainItem { get; private set; }
        public Item[] Extras { get; private set; }
        IRecipeAcceptor RecipeAcceptor;

        public RecipeManager(Item mainItem, Item[] extras)
        {
            MainItem = mainItem;
            Extras = extras;
        }

        public RecipeManager() : this(null,new Item[EXTRAS_AMOUNT])
        {
            
        }


        public void SetRecipeItem(Item item)
        {
            if (item != null && RecipeRegistry.GetRecipeBindings().ContainsKey(item.Id))
            {
                MainItem = item.Clone();
                RecipeAcceptor = RecipeRegistry.GetRecipeBindings()[MainItem.Id];
            }
            else
            {
                MainItem = null;
                RecipeAcceptor = null;
            }

            Array.Clear(Extras, 0, Extras.Length);
        }

        public bool AttemptAddItem(Item item)
        {
            if (item == null)
                return false;
            bool success;
            if (MainItem == null)
                success = AttemptAddItemToMainSlot(item);
            else if (GetFirstEmptyExtraSlot() != -1)
                success = AttemptAddItemToExtra(item);
            else success = false;

            return success;

        }

        private bool AttemptAddItemToMainSlot(Item item)
        {
            if (!RecipeRegistry.GetRecipeBindings().ContainsKey(item.Id))
                return false;
            SetRecipeItem(item);
            return true;
        }

        private bool AttemptAddItemToExtra(Item item)
        {
            if (GetFirstEmptyExtraSlot() == -1)
                return false;
            if (!RecipeAcceptor.IsExtraFit(MainItem, item, GetPlainExtras()))
                return false;
            if (GetPlainExtras().Any(x => x.Id == item.Id))
                return false;

            Extras[GetFirstEmptyExtraSlot()] = item.Clone();
            return true;
        }

        public int GetFirstEmptyExtraSlot()
        {
            return Array.IndexOf(Extras, null);
        }

        public View GetResultDisplay(Context context)
        {
            
            if (RecipeAcceptor == null)
                return null;
            return RecipeAcceptor.DisplayResult(MainItem, GetPlainExtras(), context);
        }

        public Item CalculateResult()
        {
            if (RecipeAcceptor == null)
                return null;

            return RecipeAcceptor.CalculateResult(MainItem, GetPlainExtras());
        }

        public List<Item> CalculateCost()
        {
            if (RecipeAcceptor == null)
                return null;
            return RecipeAcceptor.CalculateCost(MainItem, GetPlainExtras());
        }
        
        /// <summary>
        /// Get extras not as slots array but as a plain list of extras (no null)
        /// </summary>
        /// <returns></returns>
        public Item[] GetPlainExtras()
        {
            return Extras.Where(x => x != null).ToArray();
        }

        public void Reset()
        {
            SetRecipeItem(null);
        }
    }
}

(我没有添加 CraftingBench 和 CostListView,因为它们仅由配方经理使用,并且错误不可能出现在它们中,因为两者都不起作用,但如果需要任何澄清,请告诉我)

非常感谢任何帮助!

android xamarin android-fragments android-recyclerview notifydatasetchanged
1个回答
0
投票

我已经成功解决了这个问题。 正如预期的那样,它位于 CraftFragment 和 CraftAdapter 上: 每次重置视图时,我都会重置适配器,并且事件的 BindListener 仍会调用前一个视图。因此,在调试时仍然显示输入,但实际上并未更新当前视图。 我暂时解决了这个问题,方法是在片段中仅创建一个 CraftAdapter 实例并在每次 OnViewCreate 时更新其视图。

© www.soinside.com 2019 - 2024. All rights reserved.