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
相关产品推荐
相关产品推荐

