EaseUI 使用指南


简介

EaseUI 封装了 IM 功能常用的控件(如聊天会话、会话列表、联系人列表)。旨在帮助开发者快速集成环信 SDK。

源码地址:

快速集成

方法1:

  1. 集成 EaseUI 前的准备工作,首先需要集成环信 iOS SDK
  2. 参考 ChatDemo3.0 导入的方式,直接将EaseUI拖入项目里

方法2:

通过 Cocoapods 来集成 EaseUI:

pod 'EaseUI', :git => 'https://github.com/easemob/easeui-ios-cocoapods.git'

初始化

第 1 步:引入相关头文件 #import “EaseUI.h”。

第 2 步:在工程的 AppDelegate 中的以下方法中,调用 EaseUI 对应方法。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[EaseSDKHelper shareHelper] easemobApplication:application
didFinishLaunchingWithOptions:launchOptions
appkey:@"douser#istore"
apnsCertName:@"istore_dev"
otherConfig:@{kSDKConfigEnableConsoleLogger:[NSNumber numberWithBool:YES]}];
return YES;
}

聊天会话

创建聊天会话,传递用户或群 ID 和会话类型(EMConversationType)。

EaseMessageViewController *chatController = [[EaseMessageViewController alloc] initWithConversationChatter:@"8001" conversationType:eConversationTypeChat];

聊天会话功能扩展

EaseUI 提供现成的聊天会话 ViewController,可以通过继承 EaseMessageViewController 方式(参考 ChatDemo-UI3.0 中 ChatViewController)实现对聊天会话的扩展。

也可以直接使用 EaseMessageViewController,通过 EaseMessageViewControllerDelegate 和 EaseMessageViewControllerDataSource 两个协议实现对 EaseMessageViewController 的扩展。

实现自定义聊天样式

EaseMessageViewControllerDelegate

获取自定义消息 cell,根据 messageModel,用户自己判断是否显示自定义消息 cell,如果返回 nil 会显示默认,如果返回 cell 会显示用户自定义消息 cell。

/*!
@method
@brief 获取消息自定义cell
@discussion 用户根据messageModel判断是否显示自定义cell,返回nil显示默认cell,否则显示用户自定义cell
@param tableView 当前消息视图的tableView
@param messageModel 消息模型
@result 返回用户自定义cell
*/
- (UITableViewCell *)messageViewController:(UITableView *)tableView
cellForMessageModel:(id<IMessageModel>)messageModel;
 
/*!
@method
@brief 获取消息cell高度
@discussion 用户根据messageModel判断,是否自定义显示cell的高度
@param viewController 当前消息视图
@param messageModel 消息模型
@param cellWidth 视图宽度
@result 返回用户自定义cell
*/
- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
heightForMessageModel:(id<IMessageModel>)messageModel
withCellWidth:(CGFloat)cellWidth;
 
//具体创建自定义Cell的样例:
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)model
{
//样例为如果消息是文本消息显示用户自定义cell
if (model.bodyType == eMessageBodyType_Text) {
NSString *CellIdentifier = [CustomMessageCell cellIdentifierWithModel:model];
//CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
CustomMessageCell *cell = (CustomMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.model = model;
return cell;
}
return nil;
}
 
- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
heightForMessageModel:(id<IMessageModel>)messageModel
withCellWidth:(CGFloat)cellWidth
{
//样例为如果消息是文本消息使用用户自定义cell的高度
if (messageModel.bodyType == eMessageBodyType_Text) {
//CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
return [CustomMessageCell cellHeightWithModel:messageModel];
}
return 0.f;
}

通过自定义cell展示动态表情的效果图:

选中消息的回调。

/*!
@method
@brief 选中消息的回调
@discussion 用户根据messageModel判断,是否自定义处理消息选中时间,返回YES为自定义处理,返回NO为默认处理
@param viewController 当前消息视图
@param messageModel 消息模型
@result 是否采用自定义处理
*/
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didSelectMessageModel:(id<IMessageModel>)messageModel;
 
//选中消息回调的样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didSelectMessageModel:(id<IMessageModel>)messageModel
{
BOOL flag = NO;
//样例为如果消息是文件消息用户自定义处理选中逻辑
switch (messageModel.bodyType) {
case eMessageBodyType_Image:
case eMessageBodyType_Location:
case eMessageBodyType_Voice:
case eMessageBodyType_Video:
break;
case eMessageBodyType_File:
{
flag = YES;
NSLog(@"用户自定义实现");
}
break;
default:
break;
}
return flag;
}

用户选中头像的回调。

/*!
@method
@brief 点击消息头像
@discussion 获取用户点击头像回调
@param viewController 当前消息视图
@param messageModel 消息模型
@result
*/
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectAvatarMessageModel:(id<IMessageModel>)messageModel;
 
//获取用户点击头像回调的样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectAvatarMessageModel:(id<IMessageModel>)messageModel
{
//UserProfileViewController用户自定义的个人信息视图
//样例的逻辑是选中消息头像后,进入该消息发送者的个人信息
UserProfileViewController *userprofile = [[UserProfileViewController alloc] initWithUsername:messageModel.message.from];
[self.navigationController pushViewController:userprofile animated:YES];
}

录音按钮状态的回调

/*!
@method
@brief 底部录音功能按钮状态回调
@discussion 获取底部录音功能按钮状态回调,根据EaseRecordViewType,用户自定义处理UI的逻辑
@param viewController 当前消息视图
@param recordView 录音视图
@param type 录音按钮当前状态
@result
*/
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectRecordView:(UIView *)recordView
withEvenType:(EaseRecordViewType)type;
 
//录音按钮状态的回调样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectRecordView:(UIView *)recordView
withEvenType:(EaseRecordViewType)type
{
/*
EaseRecordViewTypeTouchDown,//录音按钮按下
EaseRecordViewTypeTouchUpInside,//手指在录音按钮内部时离开
EaseRecordViewTypeTouchUpOutside,//手指在录音按钮外部时离开
EaseRecordViewTypeDragInside,//手指移动到录音按钮内部
EaseRecordViewTypeDragOutside,//手指移动到录音按钮外部
*/
//根据type类型,用户自定义处理UI的逻辑
switch (type) {
case EaseRecordViewTypeTouchDown:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonTouchDown];
}
}
break;
case EaseRecordViewTypeTouchUpInside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonTouchUpInside];
}
[self.recordView removeFromSuperview];
}
break;
case EaseRecordViewTypeTouchUpOutside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonTouchUpOutside];
}
[self.recordView removeFromSuperview];
}
break;
case EaseRecordViewTypeDragInside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonDragInside];
}
}
break;
case EaseRecordViewTypeDragOutside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonDragOutside];
}
}
break;
default:
break;
}
}

EaseMessageViewControllerDataSource

用户判断消息是否允许长按,返回布尔值;如果用户允许长按,此方法为通知用户触发长按手势,返回布尔值,如果返回 NO 默认方式处理,返回 YES 采用用户自定义的处理方式。

/*!
@method
@brief 是否允许长按
@discussion 获取是否允许长按的回调,默认是NO
@param viewController 当前消息视图
@param indexPath 长按消息对应的indexPath
@result
*/
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
canLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
 
/*!
@method
@brief 触发长按手势
@discussion 获取触发长按手势的回调,默认是NO
@param viewController 当前消息视图
@param indexPath 长按消息对应的indexPath
@result
*/
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
 
//长按收拾回调样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
canLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
//样例给出的逻辑是所有cell都允许长按
return YES;
}
 
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
//样例给出的逻辑是长按cell之后显示menu视图
id object = [self.dataArray objectAtIndex:indexPath.row];
if (![object isKindOfClass:[NSString class]]) {
EaseMessageCell *cell = (EaseMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[cell becomeFirstResponder];
self.menuIndexPath = indexPath;
[self _showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.model.bodyType];
}
return YES;
}

demo3.0实现的消息长按效果演示:

将 EMMessage 类型转换为符合 <IMessageModel> 协议的类型,设置用户信息、消息显示用户昵称和头像。

/*!
@method
@brief 将EMMessage类型转换为符合<IMessageModel>协议的类型
@discussion 将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像
@param viewController 当前消息视图
@param EMMessage 聊天消息对象类型
@result 返回<IMessageModel>协议的类型
*/
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
modelForMessage:(EMMessage *)message;
 
//具体样例:
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
modelForMessage:(EMMessage *)message
{
//用户可以根据自己的用户体系,根据message设置用户昵称和头像
id<IMessageModel> model = nil;
model = [[EaseMessageModel alloc] initWithMessage:message];
model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];//默认头像
model.avatarURLPath = @"";//头像网络地址
model.nickname = @"昵称";//用户昵称
return model;
}

聊天会话页面头像和昵称的效果演示:

聊天会话样式自定义

聊天样式的自定义需要在 EaseMessageViewController 中 viewDidload 结束前设置。

//@property中带有UI_APPEARANCE_SELECTOR,都可以通过set的形式设置样式,具体可以参考EaseBaseMessageCell.h,EaseMessageCell.h
 
[[EaseBaseMessageCell appearance] setSendBubbleBackgroundImage:[[UIImage imageNamed:@"chat_sender_bg"] stretchableImageWithLeftCapWidth:5 topCapHeight:35]];//设置发送气泡
[[EaseBaseMessageCell appearance] setRecvBubbleBackgroundImage:[[UIImage imageNamed:@"chat_receiver_bg"] stretchableImageWithLeftCapWidth:35 topCapHeight:35]];//设置接收气泡
 
[[EaseBaseMessageCell appearance] setAvatarSize:40.f];//设置头像大小
[[EaseBaseMessageCell appearance] setAvatarCornerRadius:20.f];//设置头像圆角

消息发送

EaseSDKHelper封装了发送消息的方法。

具体发送消息样例:

/*
eMessageTypeChat 单聊消息
eMessageTypeGroupChat 群聊消息
eMessageTypeChatRoom 聊天室消息
*/
 
//发送文字消息
EMMessage *message = [EaseSDKHelper sendTextMessage:@"要发送的消息"
to:@"6001"//接收方
messageType:eMessageTypeChat//消息类型
requireEncryption:NO//是否加密
messageExt:nil];//扩展信息
//发送位置消息
EMMessage *message = [EaseSDKHelper sendLocationMessageWithLatitude:35.1//经度
longitude:35.1//纬度
address:"地址"
to:@"6001"//接收方
messageType:eMessageTypeChat//消息类型
requireEncryption:NO//是否加密
messageExt:nil];//扩展信息
 
//发送图片消息
EMMessage *message = [EaseSDKHelper sendImageMessageWithImage:image//发送的图片
to:@"6001"//接收方
messageType:eMessageTypeChat//消息类型
requireEncryption:NO//是否加密
messageExt:nil//扩展信息
quality:1.0f//图片质量(0-1)
progress:nil];//进度回调
 
//发送音频消息
EMMessage *message = [EaseSDKHelper sendVoiceMessageWithLocalPath:localPath//音频本地地址
duration:duration//语音的时长,单位是秒
to:@"6001"//接收方
messageType:eMessageTypeChat//消息类型
requireEncryption:NO//是否加密
messageExt:nil//扩展信息
progress:nil];//进度回调
//发送视频文件消息
EMMessage *message = [EaseSDKHelper sendVideoMessageWithURL:url//发送的视频地址
to:@"6001"//接收方
messageType:eMessageTypeChat//消息类型
requireEncryption:NO//是否加密
messageExt:nil//扩展信息
progress:nil];//进度回调

会话列表

 

会话列表初始化

EaseConversationListViewController *chatListVC = [[EaseConversationListViewController alloc] init];

会话列表扩展

EaseConversationListViewControllerDataSource

用户根据conversationModel实现,实现自定义会话中最后一条消息文案的显示内容。

/*!
@method
@brief 获取最后一条消息显示的内容
@discussion 用户根据conversationModel实现,实现自定义会话中最后一条消息文案的显示内容
@param conversationListViewController 当前会话列表视图
@param IConversationModel 会话模型
@result 返回用户最后一条消息显示的内容
*/
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel;
 
 
/*!
@method
@brief 获取最后一条消息显示的时间
@discussion 用户可以根据conversationModel,自定义实现会话列表中时间文案的显示内容
@param conversationListViewController 当前会话列表视图
@param IConversationModel 会话模型
@result 返回用户最后一条消息时间的显示文案
*/
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel;
 
//最后一条消息展示内容样例
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel
{
//用户获取最后一条message,根据message的messageBodyType展示显示最后一条message对应的文案
NSString *latestMessageTitle = @"";
EMMessage *lastMessage = [conversationModel.conversation latestMessage];
if (lastMessage) {
id<IEMMessageBody> messageBody = lastMessage.messageBodies.lastObject;
switch (messageBody.messageBodyType) {
case eMessageBodyType_Image:{
latestMessageTitle = NSLocalizedString(@"message.image1", @"[image]");
} break;
case eMessageBodyType_Text:{
// 表情映射
NSString *didReceiveText = [EaseConvertToCommonEmoticonsHelper
convertToSystemEmoticons:((EMTextMessageBody *)messageBody).text];
latestMessageTitle = didReceiveText;
} break;
case eMessageBodyType_Voice:{
latestMessageTitle = NSLocalizedString(@"message.voice1", @"[voice]");
} break;
case eMessageBodyType_Location: {
latestMessageTitle = NSLocalizedString(@"message.location1", @"[location]");
} break;
case eMessageBodyType_Video: {
latestMessageTitle = NSLocalizedString(@"message.video1", @"[video]");
} break;
case eMessageBodyType_File: {
latestMessageTitle = NSLocalizedString(@"message.file1", @"[file]");
} break;
default: {
} break;
}
}
 
return latestMessageTitle;
}
 
//最后一条消息展示时间样例
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel
{
//用户获取最后一条message,根据lastMessage中timestamp,自定义时间文案显示(例如:"1分钟前","14:20")
NSString *latestMessageTime = @"";
EMMessage *lastMessage = [conversationModel.conversation latestMessage];;
if (lastMessage) {
latestMessageTime = [NSDate formattedTimeFromTimeInterval:lastMessage.timestamp];
}
return latestMessageTime;
}

会话列表最后一条消息和时间显示的效果演示:

EaseConversationListViewControllerDelegate

点击会话列表用户可以根据 conversationModel 自定义处理逻辑。

/*!
@method
@brief 获取点击会话列表的回调
@discussion 获取点击会话列表的回调后,点击会话列表用户可以根据conversationModel自定义处理逻辑
@param conversationListViewController 当前会话列表视图
@param IConversationModel 会话模型
@result
*/
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
didSelectConversationModel:(id<IConversationModel>)conversationModel;
 
//会话列表点击的回调样例
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
didSelectConversationModel:(id<IConversationModel>)conversationModel
{
//样例展示为根据conversationModel,进入不同的会话ViewController
if (conversationModel) {
EMConversation *conversation = conversationModel.conversation;
if (conversation) {
//demo的逻辑,如果是与机器人的会话,进入机器人ViewController,否侧进入正常会话ViewController
if ([[RobotManager sharedInstance] isRobotWithUsername:conversation.chatter]) {
RobotChatViewController *chatController = [[RobotChatViewController alloc] initWithConversationChatter:conversation.chatter conversationType:conversation.conversationType];
chatController.title = [[RobotManager sharedInstance] getRobotNickWithUsername:conversation.chatter];
[self.navigationController pushViewController:chatController animated:YES];
} else {
ChatViewController *chatController = [[ChatViewController alloc] initWithConversationChatter:conversation.chatter conversationType:conversation.conversationType];
chatController.title = conversationModel.title;
[self.navigationController pushViewController:chatController animated:YES];
}
}
}
}

联系人列表

 

联系人列表初始化

EaseUsersListViewController *listViewController = [[EaseUsersListViewController alloc] init];

联系人列表扩展

需要实现EMUserListViewControllerDataSource

根据buddy获取用户自定信息,联系人列表里展示昵称和头像。

/*!
@method
@brief 获取用户模型
@discussion 根据buddy获取用户自定信息,联系人列表里展示昵称和头像
@param userListViewController 当前联系人视图
@param buddy 好友的信息描述类
@result 返回用户模型
*/
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
modelForBuddy:(EMBuddy *)buddy;
 
//联系人列表扩展样例
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
modelForBuddy:(EMBuddy *)buddy
{
//用户可以根据自己的用户体系,根据buddy设置用户昵称和头像
id<IUserModel> model = nil;
model = [[EaseUserModel alloc] initWithBuddy:buddy];
model.avatarURLPath = @"";//头像网络地址
model.nickname = @"昵称";//用户昵称
return model;
}

联系人列表头像和昵称的效果演示:

环信_EaseUI 使用指南的更多相关文章

  1. 李洪强iOS开发之-环信05_EaseUI 使用指南

    李洪强iOS开发之-环信05_EaseUI 使用指南 EaseUI 使用指南 简介 EaseUI 封装了 IM 功能常用的控件(如聊天会话.会话列表.联系人列表).旨在帮助开发者快速集成环信 SDK. ...

  2. 李洪强iOS开发之-环信02.2_环信官网下载环信 SDK

    李洪强iOS开发之-环信02.2_环信官网下载环信 SDK 移动客服即时通讯云 iOS SDK 当前版本:V3.1.4 2016-07-08 [ 版本历史 ] | 开发指南 | 知识库 | Demo源 ...

  3. 李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档

    李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档 SDK 2.x 至 3.0 升级指南 环信 SDK 3.0 升级文档 3.0 中的核心类为 EMClient 类,通过 EMCl ...

  4. iOS-即时通讯-环信

    下载地址:http://www.easemob.com/downloads SDK目录讲解 1.从官网下载下来的包分为如下四部分: 环信iOS SDK 开发使用 环信iOS release note ...

  5. 环信Restfull API dotnetSDK

    Easemob.Restfull4Net 环信Restfull API dotnet的封装 支持的.Net Framework版本:4.0 API地址:http://docs.easemob.com/ ...

  6. 环信SDK集成

    利用环信SDK可以实现即时通讯,但在集成的过程中碰到了不少的坑. 注意 选择项目路径,这里以最新版环信demo为例 注意:环信的ChatDemoUI这个demo里边因为研发的同事为了照顾老版本的And ...

  7. 集成IOS 环信SDK

    集成IOS SDK 在您阅读此文档时,我们假定您已经具备了基础的 iOS 应用开发经验,并能够理解相关基础概念. 下载SDK 通过Cocoapods下载地址 不包含实时语音版本SDK(EaseMobC ...

  8. 环信SDK与Apple Watch的结合(2)

    这一篇主要是介绍怎么拖apple watch上的相关页面,附源码EMWatchOCDemo. 需要在工程中的“EMWatchOCDemo WatchKit App”中进行操作,该文件夹的结构如图 Wa ...

  9. 环信SDK与Apple Watch的结合(1)

    该系列是记录在apple watch上开发IM,用到了最近挺流行的环信IM SDK. 一.先来一段网上随处可查到的信息: 1.两种分辨率 1.65寸 312*390 1.5寸 272*340 2.开发 ...

随机推荐

  1. nvl()函数

    Oracle里面的nvl()函数 Nvl(字段名,0):如果你某个字段为空,但是你想让这个字段显示0,nvl(字段名,0) ,就是当你选择出来的时候,这个字段虽然为空,但是显示的是0,当然这个0也可以 ...

  2. 【转】ASP.NET MVC 使用 FluentScheduler 定时器计划任务

    MacBook Pro 只有四个 USB Type-C 接口是否错了? 一项新技术的诞生总会对已存在的事物造成冲击或影响,如果大家都害怕冲击与影响,那这个世界永远像现在不变就行了,大家都好好的,待在自 ...

  3. oracle学习(1)

    1.安装完oracle数据库后,远程第一次无法登陆,需要进入sys用户后,更改以此后才有效. 2.TNS去读取配置的时候,如果在环境变量中已经配置了 TNS_ADMIN 后,则直接从此目录下读取. 3 ...

  4. Linq JsRender

    http://blog.csdn.net/linfei721/article/details/8973683

  5. OC4_NSString操作

    // // main.m // OC4_NSString操作 // // Created by zhangxueming on 15/6/10. // Copyright (c) 2015年 zhan ...

  6. 关于css中的align-content属性详解

    align-content 作用: 会设置自由盒内部各个项目在垂直方向排列方式. 条件:必须对父元素设置自由盒属性display:flex;,并且设置排列方式为横向排列flex-direction:r ...

  7. Arithmetic Expression

    时间限制:2000ms 单点时限:200ms 内存限制:256MB 描述 Given N arithmetic expressions, can you tell whose result is cl ...

  8. jquery ajax php 无刷新上传文件 带 遮罩 进度条 效果的哟

    在很多项目中都会叫用户上传东西这些的,自从接触了jquery 和ajax之后就不管做什么,首先都会想到这个,我这个人呢?是比较重视客户体验的,这次我这边负责的是后台板块,然后就有一块是要求用户上传照片 ...

  9. svn 相关

    // svn相关内容,windows下的可以根据网上的,安装客户端和服务器端安装成功后,可以在服务器端中的 Repositories中建立相关的项目库文件夹,右键相应的文件夹可以复制相关的 url,一 ...

  10. js清空web用户控件的值

    假设你的用户控件里面有: <asp:DropDownList ID="DropDownList1" runat="server"> <asp: ...