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

Xamarin.Forms聊天机器人回复气泡递增重复问题求助

解决Oscova Bot回复消息重复堆叠的问题

嘿,我一眼就瞅出问题根源了——你把chatbot.MainUser.ResponseReceived事件的订阅逻辑放在了Send()方法里面!每次用户点击发送按钮调用Send()时,都会给这个事件多绑定一个处理程序,所以第一次触发时1个处理程序执行,第二次2个,以此类推,自然就出现了回复消息递增堆叠的情况。

修复步骤:

把事件订阅代码从Send()方法移到ViewModel的构造函数里,这样整个ViewModel生命周期内只会订阅一次,就不会重复触发了。

修改后的完整代码如下:

/// <summary>
/// View model for the ChatbotPage.xaml
/// </summary>
public class ChatbotPageViewModel : BaseViewModel
{
    /// <summary>
    /// A field for TextToSend
    /// </summary>
    private string _texttosend;
    /// <summary>
    /// An Instance of a new SIML Oscova Chatbot
    /// </summary>
    public OscovaBot chatbot;
    /// <summary>
    /// A collection/list of chat message items
    /// </summary>
    public ObservableCollection<ChatMessageModel> Messages { get; set; } = new ObservableCollection<ChatMessageModel>();
    /// <summary>
    /// The text that the user inputs
    /// </summary>
    public string TextToSend
    {
        get { return _texttosend; }
        set
        {
            if (_texttosend != value)
            {
                _texttosend = value;
                OnPropertyChanged();
            }
        }
    }
    /// <summary>
    /// A command for sending the users messages
    /// </summary>
    public ICommand SendCommand { get; set; }
    /// <summary>
    /// ChatPageViewModel Constructor
    /// </summary>
    public ChatbotPageViewModel()
    {
        SendCommand = new RelayCommand(Send);
        chatbot = new OscovaBot();
        var assembly = IntrospectionExtensions.GetTypeInfo(typeof(MainPage)).Assembly;
        Stream stream = assembly.GetManifestResourceStream("BluePillApp.Helpers.nice.siml");
        chatbot.Import(XDocument.Load(stream));
        chatbot.Trainer.StartTraining();

        // 将事件订阅移到构造函数,仅执行一次
        chatbot.MainUser.ResponseReceived += async (sender, args) =>
        {
            await Task.Delay(1500);
            Messages.Add(new ChatMessageModel() { Text = args.Response.Text });
        };
    }
    /// <summary>
    /// This function sends a message
    /// </summary>
    public void Send()
    {
        if (!string.IsNullOrEmpty(TextToSend))
        {
            //This adds a new message to the messages collection
            Messages.Add(new ChatMessageModel() { Text = TextToSend, User = App.User });
            
            // 移除此处的事件订阅代码
            var result = chatbot.Evaluate(TextToSend);
            result.Invoke();
            //Removes the text in the Entry after message is sent
            TextToSend = string.Empty;
        }
    }
}

为什么这样改有效?

事件订阅是累加式的——每调用一次+=,就会给事件添加一个新的处理委托。原来的代码每次发送消息都新增一个委托,导致ResponseReceived触发时所有已添加的委托都会执行,回复条数自然越来越多。把订阅放在构造函数里,整个ViewModel生命周期内只绑定一次处理程序,触发时就只会执行一次,回复消息就正常了。

额外提示

如果你的ViewModel会被多次实例化,或者需要在页面销毁时清理资源,记得在合适的时机解绑事件,避免内存泄漏:

chatbot.MainUser.ResponseReceived -= YourResponseHandler;

不过在当前场景下,只要把订阅移到构造函数,就能直接解决你的重复回复问题啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:29:05