我的VSTO之路(五):Outlook初步开发之联系人扩展
2016-01-13 08:51
465 查看
原文:我的VSTO之路(五):Outlook初步开发之联系人扩展上一讲我们完成对Word的介绍,文本开始,我将着重介绍Outlook。Outlook是微软Office中一个非常实用的工具,尤其在一个拥有WindowsDomain的公司局域网中,Outlook是员工最常用的通讯工具,所以对Outlook实行进一步的定制开发的需求量是很大的。本文中,我先以联系人的扩展为开始,讲解如何开发一个强大的Outlook插件。
)。他们希望在Outlook的联系人信息上加入对方父母生日信息,方便他们做市场营销(嘿嘿,怎么营销大家自己想咯
)。同时,最好能够和Outlook原来的联系人界面保持一致便于查阅。为了不辜负同事的期望,你打开了VisualStudio……
简单思索过后,你在脑海中浮现了一下两个功能点:
OutlookFormRegion:用于制作界面,可以和原本的Outlook界面整合在一起。
ContactUserDefineFields:用于保存新加入的属性。
而新的联系人界面,你打算画成这样:
业务逻辑:每次Contact界面展示的时候,我们制作的FormRegion会读联系人中用户自定义属性里面的值(我们分别为父母的名字和生日创建4个用户属性),并展示在界面上。当Contact关闭的时候,如果用户改变了这四个控件的值,我们将其写回到自定义属性中去。关于用户自定义的属性,如下图:
OutlookObjectModel介绍
正式开始之前,我们先了解一下Outlook的对象模型。
Microsoft.Office.Interop.Outlook.Application
Outlook中的Application对象就像我在之前在Word中介绍过的Application对象一样,是所有对象的最顶层。即便你同时开多个Outlook,你也只创建了一个Application(进程也只有一个)。Application对象中,我们需要重点关注三个地方:
CreateItem方法:通过这个方法,我们创建新的Outlook对象,例如Email、Task、Contact等。
Explorers属性:获得当前的Outlook.Explorer对象集合。
Inspectors属性:获得当前的Outlook.Inspector对象集合。
有很多方法可以获得Application对象,比较常用的是直接在Addin工程中,通过Globals.ThisAddIn.Application获得。如果你看过我之前写的Word插件,你会发现这里是和WordVSTO,其实这是微软为我们设定的模式。包括在之后的Excel和PowerPoint中也都是这样的。我这里进一步介绍一下Globals,它是一个在ThisAddIn.Designer.cs中定义的一个类,对于Outlook来说,它定义了三个静态属性,ThisAddin、Ribbons和Inspectors对象。Globals作用是,通过它我们可以在Addin项目的任何位置获得我们所需要的上下文。
Microsoft.Office.Interop.Outlook.Explorer
Explorer类,即当前Outlook的主窗口。示显示包含项(如电子邮件、任务或约会)的文件夹内容的窗口。Explorer类包括可用来修改窗口的方法和属性,以及窗口更改时所引发的事件。需要注意的是,Outlook是可以开多个Explorer,但是只有一个Application。这点和Word类似,而和我们以后会讲到的Excel不同。一般我们通过Globals.ThisAddIn.Application.ActiveExplorer()方法来获得当前(焦点所在)的Explorer。
Microsoft.Office.Interop.Outlook.Inspector
Inspector类,即一个OutlookItem的窗口,比如你写邮件时弹出的窗口就是一个Inspector,你创建一个新的联系人也是一个Inspector。Inspector类是在开发Outlook插件中很常用的。尤其是以下几个地方:
获得当前的Inspector:Globals.ThisAddIn.Application.ActiveInspector(),很多时候我们都会通过这个方法获得现在的Inspector,但是这个不一定靠的住,我在今天的例子中就会讲到一种特殊情况。
新Inspector创建事件:Globals.ThisAddIn.Application.Inspectors.NewInspector,如果你需要为每个Email加一个TaskPane,就需要使用到这个事件。
获得Inspector对应的Outlook对象:Inspector.CurrentItem,Inspector只是一个窗口,而这个窗口背后的Outlook对象,则需要通过这个方法取得。
Microsoft.Office.Interop.Outlook.MAPIFolder
MAPIFolder即Outlook中的目录,Outlook中提供了16种内建的目录类型,由枚举Microsoft.Office.Interop.Outlook.OlDefaultFolders定义。
Microsoft.Office.Interop.Outlook.MailItem
Microsoft.Office.Interop.Outlook.AppointmentItem
Microsoft.Office.Interop.Outlook.TaskItem
Microsoft.Office.Interop.Outlook.ContactItem
分别对应Outlook中的Email、MeetingRequest、Task和Contact,它们都可以通过Application对象的CreateItem方法来创建。
OutlookFormRegion
介绍
为了更好地制作界面,我们使用的是OutlookFormRegion。它是从Outlook2007开始,微软进入一项新的技术。它提供一种更加方便的方式扩展Outlook项目的界面。相对之前的CustomForm,FormRegion是基于.net,开发更加容易,而且和Outlook本身,结合得更加紧密。
创建FormRegion
首先,我们添加一个新的Item,选择Office项目类型中的OutlookFormRegion
我们选择设计一个新的FormRegion
FormRegion的类型为Adjoining,即增加在页面的底部。
如果你需要在RegionForm上添加比较多的控件,你也可以选择Separate,这样你就会有一个完整的空Form。它成为一个独立的标签页,不合原始的Form冲突。
为FormRegion起名字,并且设定在编辑模式和阅读模式中都显示我们的RegionForm。
我们的FormRegion是嵌入在Contact中的。
完成了这一系列的配置之后,VS会帮我们创建一个空的FormRegion,如果需要修改刚才的设置,可以它在属性中修改,如下图。
我们开始往这个Form上添加控件,一共两个textbox、两个datetimepicker:
业务逻辑实现
流程图
这是根据我们的业务逻辑代码制作的流程图。
源代码分析
成员变量
[code]privateconststringPROPERTY_NAME_MOTHER_NAME="PROPERTYNAMEMOTHERNAME";
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
FormRegionShowing事件,这里我们从Contact的用户自定义属性中取得值,并赋值给控件。如果这些属性不存在,我们则创建它们。同时我们所有的控件都绑定了Changed事件,便于我们判断值是否改变。这里有一个需要注意的地方,这里我需要获得Contact对象才能读取Property,但是如果你的FormRegion是Adjoining模式的,在FormRegionShowing事件中,你会发现你通过Globals.ThisAddIn.Application.ActiveInspector()是不能取到Inspector的,进一步你也不能通过Inspector获得CurrentItem。这个问题在微软的论坛上都很少被提及。我这里所采用的方式是((EmployeeFamilyForm)sender).OutlookItem。可以看如下的代码:
[code]{
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
content_Changed和contact_Write事件
[code]{
[/code]
EmployeeFamilyForm_FormRegionClosed事件
[code]{
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
后记
自此我们已经完成了对Outlook联系人的扩展,在本文中我们介绍了OutlookFormRegion和UserProperties的使用,基本圆满完成了市场部的需求。话说IT帮他们实现这个需求之后,过了几天市场部的同事又来他们了。因为客户的人数比较多,最好能做一个查询工具希望可以做一个查询工具,来方便他们检索内容。至于如何检索Outlook内部对象的方法,且听下回分解。
最后,本文欢迎转载,但请保留出处,大家如果有问题,可以联系我justin.tyrael@gmail.com或者到VSTO之路小组中提问。本文所涉及的源代码可以在这里下载。
故事的开始
首先我们假设一个场景。有一天,市场部的同事来找你帮个小忙(有经验的人都知道,一般这都是无尽痛苦的开始)。他们希望在Outlook的联系人信息上加入对方父母生日信息,方便他们做市场营销(嘿嘿,怎么营销大家自己想咯
)。同时,最好能够和Outlook原来的联系人界面保持一致便于查阅。为了不辜负同事的期望,你打开了VisualStudio……
简单思索过后,你在脑海中浮现了一下两个功能点:
OutlookFormRegion:用于制作界面,可以和原本的Outlook界面整合在一起。
ContactUserDefineFields:用于保存新加入的属性。
而新的联系人界面,你打算画成这样:
业务逻辑:每次Contact界面展示的时候,我们制作的FormRegion会读联系人中用户自定义属性里面的值(我们分别为父母的名字和生日创建4个用户属性),并展示在界面上。当Contact关闭的时候,如果用户改变了这四个控件的值,我们将其写回到自定义属性中去。关于用户自定义的属性,如下图:
OutlookObjectModel介绍
正式开始之前,我们先了解一下Outlook的对象模型。
Microsoft.Office.Interop.Outlook.Application
Outlook中的Application对象就像我在之前在Word中介绍过的Application对象一样,是所有对象的最顶层。即便你同时开多个Outlook,你也只创建了一个Application(进程也只有一个)。Application对象中,我们需要重点关注三个地方:
CreateItem方法:通过这个方法,我们创建新的Outlook对象,例如Email、Task、Contact等。
Explorers属性:获得当前的Outlook.Explorer对象集合。
Inspectors属性:获得当前的Outlook.Inspector对象集合。
有很多方法可以获得Application对象,比较常用的是直接在Addin工程中,通过Globals.ThisAddIn.Application获得。如果你看过我之前写的Word插件,你会发现这里是和WordVSTO,其实这是微软为我们设定的模式。包括在之后的Excel和PowerPoint中也都是这样的。我这里进一步介绍一下Globals,它是一个在ThisAddIn.Designer.cs中定义的一个类,对于Outlook来说,它定义了三个静态属性,ThisAddin、Ribbons和Inspectors对象。Globals作用是,通过它我们可以在Addin项目的任何位置获得我们所需要的上下文。
Microsoft.Office.Interop.Outlook.Explorer
Explorer类,即当前Outlook的主窗口。示显示包含项(如电子邮件、任务或约会)的文件夹内容的窗口。Explorer类包括可用来修改窗口的方法和属性,以及窗口更改时所引发的事件。需要注意的是,Outlook是可以开多个Explorer,但是只有一个Application。这点和Word类似,而和我们以后会讲到的Excel不同。一般我们通过Globals.ThisAddIn.Application.ActiveExplorer()方法来获得当前(焦点所在)的Explorer。
Microsoft.Office.Interop.Outlook.Inspector
Inspector类,即一个OutlookItem的窗口,比如你写邮件时弹出的窗口就是一个Inspector,你创建一个新的联系人也是一个Inspector。Inspector类是在开发Outlook插件中很常用的。尤其是以下几个地方:
获得当前的Inspector:Globals.ThisAddIn.Application.ActiveInspector(),很多时候我们都会通过这个方法获得现在的Inspector,但是这个不一定靠的住,我在今天的例子中就会讲到一种特殊情况。
新Inspector创建事件:Globals.ThisAddIn.Application.Inspectors.NewInspector,如果你需要为每个Email加一个TaskPane,就需要使用到这个事件。
获得Inspector对应的Outlook对象:Inspector.CurrentItem,Inspector只是一个窗口,而这个窗口背后的Outlook对象,则需要通过这个方法取得。
Microsoft.Office.Interop.Outlook.MAPIFolder
MAPIFolder即Outlook中的目录,Outlook中提供了16种内建的目录类型,由枚举Microsoft.Office.Interop.Outlook.OlDefaultFolders定义。
Microsoft.Office.Interop.Outlook.MailItem
Microsoft.Office.Interop.Outlook.AppointmentItem
Microsoft.Office.Interop.Outlook.TaskItem
Microsoft.Office.Interop.Outlook.ContactItem
分别对应Outlook中的Email、MeetingRequest、Task和Contact,它们都可以通过Application对象的CreateItem方法来创建。
OutlookFormRegion
介绍
为了更好地制作界面,我们使用的是OutlookFormRegion。它是从Outlook2007开始,微软进入一项新的技术。它提供一种更加方便的方式扩展Outlook项目的界面。相对之前的CustomForm,FormRegion是基于.net,开发更加容易,而且和Outlook本身,结合得更加紧密。
创建FormRegion
首先,我们添加一个新的Item,选择Office项目类型中的OutlookFormRegion
我们选择设计一个新的FormRegion
FormRegion的类型为Adjoining,即增加在页面的底部。
如果你需要在RegionForm上添加比较多的控件,你也可以选择Separate,这样你就会有一个完整的空Form。它成为一个独立的标签页,不合原始的Form冲突。
为FormRegion起名字,并且设定在编辑模式和阅读模式中都显示我们的RegionForm。
我们的FormRegion是嵌入在Contact中的。
完成了这一系列的配置之后,VS会帮我们创建一个空的FormRegion,如果需要修改刚才的设置,可以它在属性中修改,如下图。
我们开始往这个Form上添加控件,一共两个textbox、两个datetimepicker:
业务逻辑实现
流程图
这是根据我们的业务逻辑代码制作的流程图。
源代码分析
成员变量
//自定义的属性名字
[code]privateconststringPROPERTY_NAME_MOTHER_NAME="PROPERTYNAMEMOTHERNAME";
privateconststringPROPERTY_NAME_MOTHER_BIRTHDAY="PROPERTYNAMEMOTHERBIRTHDAY";
privateconststringPROPERTY_NAME_FATHER_NAME="PROPERTYNAMEFATHERNAME";
privateconststringPROPERTY_NAME_FATHER_BIRTHDAY="PROPERTYNAMEFATHERBIRTHDAY";
//自定义属性对象
privateOutlook.UserProperty_MotherNameProperty=null;
privateOutlook.UserProperty_MotherBirthdayProperty=null;
privateOutlook.UserProperty_FatherNameProperty=null;
privateOutlook.UserProperty_FatherBirthdayProperty=null;
//对应的Contact对象
publicOutlook.ContactItem_Contact=null;
//标记是否内容修改
privatebool_Changed=false;
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
FormRegionShowing事件,这里我们从Contact的用户自定义属性中取得值,并赋值给控件。如果这些属性不存在,我们则创建它们。同时我们所有的控件都绑定了Changed事件,便于我们判断值是否改变。这里有一个需要注意的地方,这里我需要获得Contact对象才能读取Property,但是如果你的FormRegion是Adjoining模式的,在FormRegionShowing事件中,你会发现你通过Globals.ThisAddIn.Application.ActiveInspector()是不能取到Inspector的,进一步你也不能通过Inspector获得CurrentItem。这个问题在微软的论坛上都很少被提及。我这里所采用的方式是((EmployeeFamilyForm)sender).OutlookItem。可以看如下的代码:
privatevoidEmployeeFamilyForm_FormRegionShowing(objectsender,System.EventArgse)
[code]{
//获得FormRegion所对应的Contact对象
_Contact=((EmployeeFamilyForm)sender).OutlookItemasOutlook.ContactItem;
//从联系人的自定义属性中,获得母亲姓名属性
_MotherNameProperty=_Contact.UserProperties.Find(PROPERTY_NAME_MOTHER_NAME,Type.Missing);
if(_MotherNameProperty!=null)
{
//如果存在这个属性,则取出Value为控件赋值
tbMotherName.Text=_MotherNameProperty.ValueasString;
}
else
{
//不存在则创建这个属性
_MotherNameProperty=_Contact.UserProperties.Add(PROPERTY_NAME_MOTHER_NAME,Outlook.OlUserPropertyType.olText,Type.Missing,Type.Missing);
}
//母亲生日,原理相同
_MotherBirthdayProperty=_Contact.UserProperties.Find(PROPERTY_NAME_MOTHER_BIRTHDAY,Type.Missing);
if(_MotherBirthdayProperty!=null)
{
dtpMotherBirthday.Value=(DateTime)_MotherBirthdayProperty.Value;
}
else
{
_MotherBirthdayProperty=_Contact.UserProperties.Add(PROPERTY_NAME_MOTHER_BIRTHDAY,Outlook.OlUserPropertyType.olDateTime,Type.Missing,Type.Missing);
}
//父亲姓名
_FatherNameProperty=_Contact.UserProperties.Find(PROPERTY_NAME_FATHER_NAME,Type.Missing);
if(_FatherNameProperty!=null)
{
tbFatherName.Text=_FatherNameProperty.ValueasString;
}
else
{
_FatherNameProperty=_Contact.UserProperties.Add(PROPERTY_NAME_FATHER_NAME,Outlook.OlUserPropertyType.olText,Type.Missing,Type.Missing);
}
//父亲生日
_FatherBirthdayProperty=_Contact.UserProperties.Find(PROPERTY_NAME_FATHER_BIRTHDAY,Type.Missing);
if(_FatherBirthdayProperty!=null)
{
dtpFatherBirthday.Value=(DateTime)_FatherBirthdayProperty.Value;
}
else
{
_FatherBirthdayProperty=_Contact.UserProperties.Add(PROPERTY_NAME_FATHER_BIRTHDAY,Outlook.OlUserPropertyType.olDateTime,Type.Missing,Type.Missing);
}
//将这四个控件绑定change事件,只有在修改之后,我们才会将值回写到Contact对应的属性中去
tbMotherName.TextChanged+=newEventHandler(content_Changed);
dtpMotherBirthday.ValueChanged+=newEventHandler(content_Changed);
tbFatherName.TextChanged+=newEventHandler(content_Changed);
dtpFatherBirthday.ValueChanged+=newEventHandler(content_Changed);
//在Write事件中,把修改的值保存到属性中去
_Contact.Write+=newMicrosoft.Office.Interop.Outlook.ItemEvents_10_WriteEventHandler(contact_Write);
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
content_Changed和contact_Write事件
voidcontent_Changed(objectsender,EventArgse)
[code]{
//有修改时,将_Change置为true
_Changed=true;
}
voidcontact_Write(refboolCancel)
{
if(_Changed)
{
//保存值到属性中去
_MotherNameProperty.Value=tbMotherName.Text.Trim();
_MotherBirthdayProperty.Value=dtpMotherBirthday.Value;
_FatherNameProperty.Value=tbFatherName.Text.Trim();
_FatherBirthdayProperty.Value=dtpFatherBirthday.Value;
}
}
[/code]
EmployeeFamilyForm_FormRegionClosed事件
privatevoidEmployeeFamilyForm_FormRegionClosed(objectsender,System.EventArgse)
[code]{
//关闭事件绑定
_Contact.Write-=newMicrosoft.Office.Interop.Outlook.ItemEvents_10_WriteEventHandler(contact_Write);
//释放对象
System.Runtime.InteropServices.Marshal.ReleaseComObject(_Contact);
_Contact=null;
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
后记
自此我们已经完成了对Outlook联系人的扩展,在本文中我们介绍了OutlookFormRegion和UserProperties的使用,基本圆满完成了市场部的需求。话说IT帮他们实现这个需求之后,过了几天市场部的同事又来他们了。因为客户的人数比较多,最好能做一个查询工具希望可以做一个查询工具,来方便他们检索内容。至于如何检索Outlook内部对象的方法,且听下回分解。
最后,本文欢迎转载,但请保留出处,大家如果有问题,可以联系我
相关文章推荐
- 中文Ubuntu主目录下的文档文件夹改回英文
- 不把项目添加到tomcat目录下发布的处理(转)
- (转载)Mysql导入数据相当慢
- 我的VSTO之路(四):深入介绍Word开发
- jquery对复选框(checkbox)的操作汇总
- Android自定义ViewPager可控制是否滑动
- Oracle Database 实例关闭和启动 浅谈
- C语言学习之字符串、字符和字节第二讲
- 我的VSTO之路(三):Word基本知识
- Android编程获取全局Context的方法
- 郭广昌:致复星全球合伙人的一封信
- 我的VSTO之路(二):VSTO程序基本知识
- POJ 2455 Secret Milking Machine(搜索-二分,网络流-最大流)
- Oracle错误——ORA-03113:通信通道的文件结尾 解决办法
- GO逆转字符串
- 键盘和输入框上移
- sqlite数据库,进行批量执行.sql文件的时候,会出现一个:not an error的错误提示
- oracle 表空间(数据文件)满了后 修改表空间大小
- 『史上最简单的问题解决手册』读书笔记--如何更加了解他人
- Python网络02 Python服务器进化