交互逻辑和UI说明
UI结构概述
LLM Agent采用三列布局结构:
- 左侧导航栏 - 固定宽度,包含主要功能导航按钮
- 中间内容列表 - 根据当前功能显示对应的列表内容
- 右侧主内容区 - 显示主要交互内容
整个UI设计采用嵌套SplitContainer实现分区显示,确保内容区域大小可灵活调整。
主要控件层次结构
LlmAgentMainForm
├── mainSplitContainer
│ ├── Panel1 (导航栏)
│ │ └── navPanel
│ │ ├── avatarButton
│ │ ├── chatNavButton
│ │ ├── channelNavButton
│ │ ├── websiteNavButton
│ │ ├── promptsNavButton
│ │ └── settingsNavButton
│ │
│ └── Panel2 (内容区)
│ ├── chatPagePanel
│ │ └── chatPageSplitContainer
│ │ ├── Panel1 (聊天列表)
│ │ │ └── chatListContainer
│ │ │ ├── Panel1 (搜索和新建)
│ │ │ │ ├── searchBox
│ │ │ │ └── newChatButton
│ │ │ └── Panel2 (聊天列表)
│ │ │ └── chatListPanel
│ │ │
│ │ └── Panel2 (聊天内容)
│ │ └── inputPanel
│ │
│ ├── channelPanel
│ │ └── channelPageSplitContainer
│ │ ├── Panel1 (渠道列表)
│ │ │ └── channelListPanel
│ │ │ └── channelListBox
│ │ └── Panel2 (渠道详情)
│ │ └── channelDetailsPanel
│ │
│ ├── aiWebsitePanel
│ │ └── aiWebsitePageSplitContainer
│ │ ├── Panel1 (网站列表)
│ │ │ └── aiWebsiteMenuPanel
│ │ │ └── websiteListContainer
│ │ │ ├── Panel1 (搜索和新建)
│ │ │ │ ├── websiteSearchBox
│ │ │ │ └── newWebsiteButton
│ │ │ └── Panel2 (网站列表)
│ │ │ └── websiteListPanel
│ │ └── Panel2 (网站内容)
│ │ └── aiWebsiteContentPanel
│ │
│ ├── userProfilePanel
│ │ └── userProfilePageSplitContainer
│ │ ├── Panel1 (用户列表)
│ │ │ └── userProfileMenuPanel
│ │ │ └── userListContainer
│ │ │ ├── Panel1 (搜索和新建)
│ │ │ │ ├── userSearchBox
│ │ │ │ └── newUserButton
│ │ │ └── Panel2 (用户列表)
│ │ │ └── userListPanel
│ │ └── Panel2 (用户详情)
│ │ └── userProfileContentPanel
│ │
│ ├── promptsPanel
│ │ └── promptsPageSplitContainer
│ │ ├── Panel1 (提示词列表)
│ │ │ └── promptsListContainer
│ │ │ ├── Panel1 (搜索和新建)
│ │ │ │ ├── promptSearchBox
│ │ │ │ └── newPromptButton
│ │ │ └── Panel2 (提示词列表)
│ │ │ └── promptsListPanel
│ │ └── Panel2 (提示词内容)
│ │ └── promptsContentPanel
│ │
│ └── settingsPanel
│ └── settingsPageSplitContainer
│ ├── Panel1 (设置菜单)
│ │ └── settingsMenuPanel
│ └── Panel2 (设置内容)
│ └── settingsContentContainer
│ └── settingsContentPanel
导航流程
- 应用启动 - 默认显示chatPagePanel,激活chatNavButton
- 导航切换 - 点击左侧导航按钮,调用SwitchToPanel方法:
- 隐藏所有内容面板
- 显示对应目标面板
- 重置所有导航按钮样式
- 高亮当前活动按钮
- 执行特定面板的初始化操作
聊天功能交互流程
新建对话
- 点击"新建聊天"按钮 → 调用CreateNewChat方法
- 创建新会话,清空消息区域
- 添加系统欢迎消息
- 重新初始化聊天主题列表
- 切换到聊天界面,设置输入框焦点
发送消息
- 输入消息 → 按Ctrl+Enter或点击发送按钮
- 调用SendMessage方法
- 添加用户消息到当前会话
- 调用API获取AI响应(支持流式响应)
- 更新UI显示结果
- 更新聊天历史列表
切换历史对话
- 点击左侧会话列表中的历史项目
- 调用会话管理器切换到对应会话
- 更新UI显示选中的会话内容
设置面板交互流程
模型设置
- 选择提供商 → 触发ProviderChanged事件
- 更新模型列表
- 保存设置并更新窗体标题
API设置
- 填写API密钥和主机地址
- 点击更新按钮 → 调用UpdateApiSettings方法
- 保存配置
通用设置
- 勾选流式响应 → 更新_useStreamResponse变量
- 修改系统提示词 → 保存到Properties.Settings
控件访问关系
由于采用嵌套结构,控件的访问需要考虑层次关系:
csharp
// 示例:获取txtOutput控件
RichTextBox txtOutput = chatOutputPanel.Controls["txtOutput"] as RichTextBox;
// 示例:获取深层嵌套的控件
CheckBox chkStreamResponse = settingsContentPanel.Controls.Find("chkStreamResponse", true).FirstOrDefault() as CheckBox;
界面切换机制
界面使用Panel的Visible属性进行切换,确保同一时刻只有一个主要内容面板可见:
csharp
// 隐藏所有内容面板
foreach (Control control in mainSplitContainer.Panel2.Controls)
{
control.Visible = false;
}
// 显示目标面板
targetPanel.Visible = true;
事件处理模式
应用采用事件驱动的交互模式,主要事件处理包括:
导航事件
csharpprivate void chatNavButton_Click(object sender, EventArgs e) { SwitchToPanel(chatPagePanel, chatNavButton); }
聊天事件
csharpprivate void btnSend_Click(object sender, EventArgs e) { SendMessage(); } private void txtInput_KeyDown(object sender, KeyEventArgs e) { if (e.Control && e.KeyCode == Keys.Enter) { SendMessage(); e.Handled = true; } }
设置变更事件
csharpprivate void cboProvider_SelectedIndexChanged(object sender, EventArgs e) { if (_isUpdatingUI) return; UpdateModelList(); SaveSettings(); }
异步操作处理
聊天消息发送和接收使用异步模式,确保UI响应性:
csharp
private async Task SendMessageAsync()
{
// 显示发送中状态
SetSendingState(true);
try
{
// 异步调用API
var response = await _channelService.SendMessageAsync(message, currentChannel);
// 更新UI显示
UpdateChatDisplay(response);
}
catch (Exception ex)
{
HandleError(ex);
}
finally
{
// 恢复UI状态
SetSendingState(false);
}
}
防止事件循环
应用使用标志变量防止UI更新触发事件导致的循环:
csharp
// 用于防止界面更新时触发事件处理
private bool _isUpdatingUI = false;
private void UpdateChannelDetails(Channel channel)
{
_isUpdatingUI = true;
try
{
// 更新UI控件
txtChannelName.Text = channel.Name;
chkEnabled.Checked = channel.IsEnabled;
// ...其他UI更新
}
finally
{
_isUpdatingUI = false;
}
}
注意事项与最佳实践
控件访问一致性
- 所有控件访问应统一考虑层次结构,避免直接访问
- 使用Controls.Find方法查找深层嵌套控件
错误处理
- 在访问控件前增加null检查,提高应用稳定性
- 使用try-catch块处理可能的异常
UI线程同步
- 从工作线程更新UI时使用Invoke/BeginInvoke
- 确保UI操作在UI线程执行
资源释放
- 实现IDisposable接口,确保资源正确释放
- 使用using语句自动释放资源
性能优化
- 使用SuspendLayout/ResumeLayout减少重绘
- 批量更新UI,避免频繁触发布局计算