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

Unity使用委托事件调用方法时无法修改TextMeshPro文本的问题

问题描述

通过委托事件调用方法时,该方法可正常执行,但在被调用方法中尝试修改TextMeshPro文本却无任何效果。在其他方法中或直接调用该方法时均可正常修改文本,仅通过事件调用时失效,且无任何报错,遍历MatchCode的TextMeshPro组件也无结果。

相关代码

NetworkingManager 脚本

using DarkRift.Client;
using System.Net;
using System;
using DarkRift;
using Scripts.Models;
using UnityEngine;
using System.Text.RegularExpressions;

namespace Scripts.Networking {

    public class NetworkingManager
    {
        private static NetworkingManager instance;
        public bool GotMatch = false;

        private DarkRiftClient client;

        public delegate void MatchCreatedEvent(int matchId);
        public static event MatchCreatedEvent OnMatchCreated;

        public void ChangeText () {
            int matchID = 12345;
            OnMatchCreated?.Invoke(matchID);
        }
    }
}

NameForm 脚本

using Scripts.Networking;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

public class NameForm : MonoBehaviour
{
    [SerializeField]
    private TMPro.TMP_InputField InputNameField;
    public TMPro.TMP_InputField InputMatchId;
    public TMPro.TMP_Text MatchCode;

    private bool IsSubmiting = false;
    private bool LoadingScene = false;

    public delegate void MatchCodeEvent(int matchId);
    public static event MatchCodeEvent OnMatchCodeReceived;

    void Start()
    {
        NetworkingManager.OnMatchCreated += MatchCodeReceived;

        if (InputNameField == null) {
            throw new System.Exception("missing input field");
        }
        if (InputMatchId == null)
        {
            throw new System.Exception("missing input field");
        }
    }

    public void MatchCodeReceived (int MatchId)
    {
        //Debug.Log("MatchCodeReceived: " + MatchId);
        MatchCode.text = MatchId.ToString();
    }
}
解决方案

核心原因

DarkRift的网络回调事件默认在非主线程触发,而Unity所有UI操作(包括修改TextMeshPro文本)必须在主线程执行。事件触发时MatchCodeReceived在后台线程运行,修改UI的操作被Unity静默忽略,因此看不到效果也不会报错。

修复步骤

  1. 在NameForm中添加主线程任务队列,用于存放需要在主线程执行的UI操作:

    private Queue<Action> _mainThreadActions = new Queue<Action>();
    private readonly object _queueLock = new object();
    
  2. 在Update方法中处理队列任务(Update始终在主线程执行):

    void Update()
    {
        lock (_queueLock)
        {
            while (_mainThreadActions.Count > 0)
            {
                _mainThreadActions.Dequeue().Invoke();
            }
        }
    }
    
  3. 修改MatchCodeReceived,将UI操作加入主线程队列:

    public void MatchCodeReceived(int MatchId)
    {
        lock (_queueLock)
        {
            _mainThreadActions.Enqueue(() => 
            {
                MatchCode.text = MatchId.ToString();
            });
        }
    }
    

额外验证

  • 可以在MatchCodeReceived中添加日志,打印当前线程ID,确认是否为非主线程:
    Debug.Log($"当前线程ID: {System.Threading.Thread.CurrentThread.ManagedThreadId}");
    
    主线程ID通常为1,如果打印的ID不是1,就坐实了线程问题。
  • 确认NameForm对象在事件触发时没有被销毁,保证事件注册的实例仍然存在。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 08:45:25