You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity C#传递Action参数时确认窗口方法重复执行问题排查

问题分析与解决方案

核心原因

每次调用ThrowAConfirmScreen方法时,都会给confirmButton和cancelButton重复添加点击监听器。Unity的UI按钮点击事件是多播委托,每次AddListener都会往委托列表中追加新的回调方法,而你点击取消时只是隐藏窗口,并没有移除这些已添加的监听器。当多次取消再点击确认时,所有累积的监听器都会被触发,导致传入的func执行次数等于之前取消的次数。

解决方案

方案1:每次绑定前移除旧监听器

在添加新的点击监听器前,先清除按钮上已有的所有监听器,避免重复绑定:

public void ThrowAConfirmScreen(string msg, Action func)
{
    confirmField.SetActive(true);
    confirmText.text = msg;

    // 清除按钮上的所有旧监听器
    confirmButton.onClick.RemoveAllListeners();
    cancelButton.onClick.RemoveAllListeners();

    confirmButton.onClick.AddListener(() => {
        func();
        confirmField.SetActive(false);
    });

    cancelButton.onClick.AddListener(() => {
        confirmField.SetActive(false);
    });
}

方案2:初始化时单次绑定,复用逻辑

更优雅的方式是只在初始化阶段绑定一次监听器,通过变量存储当前要执行的回调,避免重复绑定:

private Action _currentConfirmAction;

void Awake()
{
    // 仅在初始化时绑定一次监听器
    confirmButton.onClick.AddListener(OnConfirmClicked);
    cancelButton.onClick.AddListener(OnCancelClicked);
    confirmField.SetActive(false);
}

public void ThrowAConfirmScreen(string msg, Action func)
{
    _currentConfirmAction = func;
    confirmText.text = msg;
    confirmField.SetActive(true);
}

private void OnConfirmClicked()
{
    _currentConfirmAction?.Invoke();
    confirmField.SetActive(false);
    _currentConfirmAction = null; // 执行后清空,避免残留
}

private void OnCancelClicked()
{
    confirmField.SetActive(false);
    _currentConfirmAction = null;
}

为什么之前的尝试无效

不管使用箭头函数、单独声明函数还是替换为Func<>,只要每次调用ThrowAConfirmScreen都执行AddListener,就会不断往按钮的委托列表中追加新的回调,因为Unity的AddListener不会覆盖已有的委托方法,只会累加。

内容的提问来源于stack exchange,提问作者crybaby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:35:27