Excel催化剂开源第12波-VSTO开发遍历功能区所有菜单按钮及自定义函数清单
在插件开发过程中,随着功能越来越多,用户找寻功能入口将变得越来越困难,在Excel催化剂 ,将采用遍历所有功能的方式,让用户可以轻松使用简单的查找功能找到想要功能所在位置,查找的范围有:功能按钮的显示名称、功能说明等。

这个遍历功能区按钮属性,不确定在xml功能区中能否实现,在设计器功能区,因其已经被强类型为一个类对象,用反射技术可以将这个Ribbon类下所有的控件及属性给遍历出来。详细可参考功能第78波说明。

同样地,自定义函数也可以用遍历的方式,列出所有自定义函数。前提是自定义函数是ExcelDna框架开发的。

代码实现
给用户一个按钮,点击后遍历到工作表中。
private void btnShowFeatures_Click(object sender, RibbonControlEventArgs e)
{
try
{
Common.ExcelApp.ScreenUpdating = false;
Common.ExcelApp.DisplayAlerts = false;
RibbonMenu ribbonMenu = sender as RibbonMenu;
GroupVisibleSetting groupVisibleSetting = new GroupVisibleSetting()
{
CurrentRibbon = this
};
groupVisibleSetting.ListTabFunctionInfo();
//遍历自定义函数清单
UdfListInfo.ListUdfInfo();
}
catch (Exception ex)
{
Common.OutMsgError(ex);
}
finally
{
Common.ExcelApp.ScreenUpdating = true;
Common.ExcelApp.DisplayAlerts = true;
}
}
做了个类,用于访问功能区的信息,里面用了反射技术,因笔者水平也是比较菜,是笔者师傅给予帮助下实现的,详细技术要点也讲不清,有兴趣深入的可以自行百度学习。
using Microsoft.Office.Tools.Excel;
using Microsoft.Office.Tools.Ribbon;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
namespace Excel催化剂
{
class GroupVisibleSetting
{
public Ribbon1 CurrentRibbon { get; set; }
public RibbonMenu MenuSwitch { get; set; }
public void ListTabFunctionInfo()
{
DataTable dt = new DataTable();
dt.Columns.Add("一级分组");
dt.Columns.Add("二级分组");
dt.Columns.Add("三级分组");
dt.Columns.Add("功能名称");
dt.Columns.Add("功能说明");
foreach (var grp in CurrentRibbon.Tabs.Cast<RibbonTab>().FirstOrDefault(s => s.Name == "excelCatalyzer").Groups)
{
foreach (var grpItem in grp.Items)
{
if (grpItem is RibbonButton)
{
var btn = grpItem as RibbonButton;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grp.Label;
dr["三级分组"] = grp.Label;
dr["功能名称"] = btn.Label;
dr["功能说明"] = btn.SuperTip;
dt.Rows.Add(dr);
}
else if (grpItem is RibbonMenu)
{
var grpItemMenu = grpItem as RibbonMenu;
MenuItemsLoad(grpItemMenu);
foreach (var grpItemMenuItem in grpItemMenu.Items)
{
if (grpItemMenuItem is RibbonButton)
{
var btn = grpItemMenuItem as RibbonButton;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = grpItemMenu.Label;
dr["功能名称"] = btn.Label;
dr["功能说明"] = btn.SuperTip;
dt.Rows.Add(dr);
}
else if (grpItemMenuItem is RibbonSeparator)
{
var btn = grpItemMenuItem as RibbonSeparator;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = grpItemMenu.Label;
dr["功能名称"] = btn.Title;
dr["功能说明"] = "分隔符,组合以下内容";
dt.Rows.Add(dr);
}
else if (grpItemMenuItem is RibbonGallery)
{
var itemGal = grpItemMenuItem as RibbonGallery;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = grpItemMenu.Label;
dr["功能名称"] = itemGal.Label;
dr["功能说明"] = itemGal.SuperTip;
dt.Rows.Add(dr);
}
else if (grpItemMenuItem is RibbonMenu)
{
var itemMenu = grpItemMenuItem as RibbonMenu;
foreach (var itemMenuItem in itemMenu.Items)
{
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grpItemMenu.Label;
dr["三级分组"] = itemMenu.Label;
if (itemMenuItem is RibbonButton)
{
var btn = itemMenuItem as RibbonButton;
dr["功能名称"] = btn.Label;
dr["功能说明"] = btn.SuperTip;
}
else if (itemMenuItem is RibbonSeparator)
{
var btn = itemMenuItem as RibbonSeparator;
dr["功能名称"] = btn.Title;
dr["功能说明"] = "分隔符,组合以下内容";
}
dt.Rows.Add(dr);
}
}
}
}
else if (grpItem is RibbonToggleButton)
{
var tglBtn = grpItem as RibbonToggleButton;
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grp.Label;
dr["三级分组"] = grp.Label;
dr["功能名称"] = tglBtn.Label;
dr["功能说明"] = tglBtn.SuperTip;
dt.Rows.Add(dr);
}
else if (grpItem is RibbonGallery)
{
var grpGal = grpItem as RibbonGallery;
foreach (var grpGalItem in grpGal.Items)
{
DataRow dr = dt.NewRow();
dr["一级分组"] = grp.Label;
dr["二级分组"] = grp.Label;
dr["三级分组"] = grp.Label;
dr["功能名称"] = grpGalItem.Label;
dr["功能说明"] = grpGalItem.SuperTip;
dt.Rows.Add(dr);
}
}
}
}
ListObject listObject = Common.CreateNewVSTOListObject("功能清单",false);
Common.OutputDataToListObject(listObject, dt, false);
}
private void MenuItemsLoad(RibbonMenu grpItemMenu)
{
if (grpItemMenu.Name == "menuNumberFormatSetting")
{
CurrentRibbon.menuNumberFormatSetting_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.NumberFormatPanelTitle);
panel.Visible = false;
}
else if (grpItemMenu.Name == "menuVisualData")
{
CurrentRibbon.menuVisualData_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.DataVisualPanelTitle);
panel.Visible = false;
}
else if (grpItemMenu.Name == "menuInsertPicture")
{
CurrentRibbon.menuInsertPicture_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.BatchPicInsertPanelTitle);
panel.Visible = false;
}
else if (grpItemMenu.Name == "menuBarCode")
{
CurrentRibbon.menuBarCode_ItemsLoading(grpItemMenu, null);
var panel = Utilities.TaskPanelUtility.GetCusTomTaskPaneByTitle(Utilities.TaskPanelUtility.QrCodePanelTitle);
panel.Visible = false;
}
}
public void GrpVisibleSetting()
{
var grpInfos = GetGrpInfosSetting();
foreach (var item in grpInfos)
{
var grp = Globals.Ribbons.Ribbon1.GetGrpByGroupName(item.GrpName);
if (grp != null)
{
grp.Visible = item.GrpVisible;
}
}
}
public void menuSwitch_ItemsLoading()
{
this.MenuSwitch.Items.Clear();
//从反射中得到grp的集合
RibbonGroup[] grpfields = GetGrpFields();
//从setting里提取grp信息
var grpInfosSetting = GetGrpInfosSetting();
foreach (var item in grpfields)
{
var grpInfo = grpInfosSetting.FirstOrDefault(s => s.GrpName == item.Name);
RibbonCheckBox control = Globals.Ribbons.Ribbon1.Factory.CreateRibbonCheckBox();
control.Name = "btn" + item.Name;
control.Label = item.Label;
control.Checked = grpInfo.GrpName != null ? grpInfo.GrpVisible : true; //当setting信息里有保存的话,用setting的信息显示关闭与否,否则用true
control.Click += Control_Click;
this.MenuSwitch.Items.Add(control);
}
}
private void Control_Click(object sender, RibbonControlEventArgs e)
{
RibbonCheckBox checkBox = sender as RibbonCheckBox;
string grpName = checkBox.Name.Substring(3);//去除btn字符
RibbonGroup grp = Globals.Ribbons.Ribbon1.GetGrpByGroupName(grpName);
grp.Visible = checkBox.Checked;
SaveSwithSetting();
}
private void SaveSwithSetting()
{
List<string> grpInfos = new List<string>();
foreach (RibbonCheckBox item in this.MenuSwitch.Items)
{
grpInfos.Add(item.Name.Substring(3) + "," + item.Label + "," + item.Checked.ToString());
}
Properties.Settings.Default.SwitchSetting = string.Join(";\n", grpInfos);
Properties.Settings.Default.Save();
}
/// <summary>
/// 反射的方式获得组的对象
/// </summary>
/// <returns></returns>
private RibbonGroup[] GetGrpFields()
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
Type t = typeof(Ribbon1);
return t.GetFields(bf)
.Where(s => s.Name.StartsWith("grp") && s.Name != "grpSwitch" && s.Name != "grpAbout")
.Select(s => Globals.Ribbons.Ribbon1.GetGrpByGroupName(s.Name))
.ToArray();
}
private (string GrpName, string GrpCaption, bool GrpVisible)[] GetGrpInfosSetting()
{
string switchSettingString = Properties.Settings.Default.SwitchSetting;
return switchSettingString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s =>
(
GrpName: s.Split(',')[0].Trim(new char[] { '\r', '\n', '\0' }),
GrpCaption: s.Split(',')[1].Trim(new char[] { '\r', '\n', '\0' }),
GrpVisible: bool.Parse(s.Split(',')[2].Trim(new char[] { '\r', '\n', '\0' }))
)
).ToArray();
}
}
}
同样地在自定义函数方面,通过在自定义函数里作了一个自定义函数,专门用于遍历自定义函数的属性,已经开源在自定义函数项目中。
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Tools.Excel;
namespace Excel催化剂
{
class UdfListInfo
{
private static string shtName = "功能清单";
internal static void ListUdfInfo()
{
try
{
Excel.Worksheet sht = Common.ExcelApp.ActiveWorkbook.Worksheets[shtName];
DataTable dt = new DataTable();
dt.Columns.Add("函数类别");
dt.Columns.Add("函数名称");
dt.Columns.Add("函数注释");
var result = Common.ExcelApp.Run("ListUdfDesc");
if (result is Array)
{
var arrResult = Utilities.ArrayUtility.ConvertExcelArrayToDotNetArray(result as Array);
foreach (var item in arrResult)
{
var strSplits = item.ToString().Split(new string[] { "#|#" }, StringSplitOptions.RemoveEmptyEntries);
if (strSplits.Length == 3)
{
DataRow dr = dt.NewRow();
dr[0] = strSplits[0];
dr[1] = strSplits[1];
dr[2] = strSplits[2];
dt.Rows.Add(dr);
}
}
Excel.Range listRange = sht.ListObjects[shtName].Range;
Excel.Range firstCell = listRange.Offset[0, listRange.Columns.Count + 2].Cells[1, 1];
Worksheet vstoSht = Globals.Factory.GetVstoObject(sht);
var listObject = vstoSht.Controls.AddListObject(firstCell, "自定义函数清单");
Common.OutputDataToListObject(listObject, dt, false);
}
}
catch (Exception)
{
}
}
}
}
上述代码中,在VSTO项目里,仅需用Application.Run就可以访问到xll里的自定义函数ListUdfDesc,同时有个小要点是自定义函数返回的数组,下标是从1开始的Excel特有的,和.net的0为下标的不一样,需要作下转换。
var arrResult = Utilities.ArrayUtility.ConvertExcelArrayToDotNetArray(result as Array);
public static object ListUdfDesc()
{
List<string> list = new List<string>();
var funcs = ExcelRegistration.GetExcelFunctions();
foreach (var funcInfo in funcs)
{
string name = funcInfo.FunctionAttribute.Name;
string desc = funcInfo.FunctionAttribute.Description.Replace("Excel催化剂出品,必属精品!", "");
string catalog = funcInfo.FunctionAttribute.Category;
if (!string.IsNullOrEmpty( catalog))
{
list.Add($"{catalog}#|#{name}#|#{desc}");
}
}
if (list.Count>0)
{
return list.ToArray();
}
else
{
return string.Empty;
}
}
public static object[] ConvertExcelArrayToDotNetArray(Array arr)
{
int lb = arr.GetLowerBound(0);
var ret = new object[arr.GetUpperBound(0) - lb + 1];
for (int ix = 0; ix < ret.Length; ++ix)
{
ret[ix] = arr.GetValue(ix + lb);
}
return ret;
}
结语
使用遍历的方式,让用户可以更轻松地查找相应功能,将极大地提升查找功能的友好度,本篇用到反射技术,比较高级的技术,若代码不甚明白,可自行进行相关知识点的学习补充。
再一次验证了VSTO给一般开发者带来的便利性,特别是在设计器功能区上,带来了强类型的Ribbon类,可轻松访问此类里的所有对象,而增加此类的内容,仅需类似Winform那般拖拉控件即可完成,敏捷开发首选。
技术交流QQ群
QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

关于Excel催化剂
Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!
Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!
Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q


取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。
最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!
关于Excel催化剂作者
姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)
技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。
擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。
2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。
和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。
技术交流QQ群
QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

关于Excel催化剂
Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!
Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!
Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q


取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。
最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!
关于Excel催化剂作者
姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)
技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。
擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。
2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。
和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。
Excel催化剂开源第12波-VSTO开发遍历功能区所有菜单按钮及自定义函数清单的更多相关文章
- Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术
Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术 Excel催化剂 2019.01.12 14:10* 字数 2948 阅读 41评论 0喜欢 0 编辑文章 在Excel催化剂的几大 ...
- Excel催化剂开源第16波-VSTO开发之脱离传统COM交互以提升性能
在VSTO开发或其他COM技术开发过程中,甚至VBA也是,在和Excel交互中,难免会遇到性能瓶颈问题,COM技术的交互实在太慢,对大量数据读写等操作,耗时太长,容易卡用户界面以为是程序死机等等. 在 ...
- Excel催化剂开源第10波-VSTO开发之用户配置数据与工作薄文件一同存储
在传统的VBA开发中,若是用的是普通加载项方法,是可以存储数据在xlam上的,若用的是Com加载项方法同时是Addins程序级别的项目开发的,配置文件没法保存到工作薄中,一般另外用配置文件来存放供调用 ...
- Excel催化剂开源第32波-VSTO开发的插件让WPS顺利调用的方法-注册表增加注册信息
VSTO插件开发完成后,鉴于现在WPS用户也不少,很多时候用户没办法用OFFICE软件,只能在WPS环境下办公,VSTO开发的插件,只需增加一句注册表信息,即可让WPS识别到并调用VSTO开发的功能, ...
- Excel催化剂开源第14波-VSTO开发之单元格区域转DataTable
在Excel开发过程中,大部分时候是和Range单元格区域打交道,在VBA开发中,大家都知道的一点是,不能动不动就去遍历所有单元格,那性能是非常糟糕的,很多时候,是需要把整个单元格区域装入数组中再作处 ...
- Excel催化剂开源第9波-VSTO开发图片插入功能,图片带事件
图片插入功能,这个是Excel插件的一大刚需,但目前在VBA接口里开发,如果用Shapes.AddPicture方法插入的图片,没法对其添加事件,且图片插入后需等比例调整纵横比例特别麻烦,特别是对于插 ...
- Excel催化剂开源第8波-VSTO开发之异步调用方法
在VSTO开发过程中,因其和普通的Winform开发有点差别,具体细节笔者也说不清楚,大概是VSTO的插件是寄生在Excel中,不属于独立的进程之类的,其异步方法调用时,未能如Winform那样直接用 ...
- Excel催化剂开源第7波-VSTO开发中Ribbon动态加载菜单
在VS开发环境中,特别是VSTO的开发,微软已经现成地给开发者准备了设计器模式的功能区开发,相对传统的VBA.ExcelDna和其他方式的COM加载项开发来说,不需要手写xml功能区,直接类似拖拉窗体 ...
- Excel催化剂开源第22波-VSTO的帮助文档在哪里?
Excel催化剂开源第22波-VSTO的帮助文档在哪里? Excel催化剂 2019.01.12 14:10 字数 2930 阅读 55评论 0喜欢 0 编辑文章 对于专业程序猿来说,查找文档不是 ...
随机推荐
- QT 设置应用程序图标和可执行程序图标(另有setWindowTitle和setWindowIcon)
首先准备个ICO图标.例如:myappico.ico用记事本新建个文件里面就写一行:IDI_ICON1 ICON DISCARDABLE "/images/myap ...
- 使用PyQt5编写一个简单的GUI程序(pyside 有 pyside-uic 把ui文件转成py文件,pyside-rcc 把qrc文件转成 py文件导入就行了)
我做Python窗口界面编程时,经常使用PyQt进行设计.这里简单叙述一下使用PyQt5制作一个简单的图形界面的流程 PyQt的简介以及开发环境的搭建在此不多赘述. 1. 打开Qt Des ...
- SqlServer 动态SQL(存储过程)中Like 传入参数无正确返回值的问题
最近在做项目时,以动态Sql进行Like语句查询时发现应该返回的结果却一直返回空,后来发现是写法错误: 错误SQL: DECLARE @0 varchar(20) SET @0 = 'XA-LZ' S ...
- git(一)
一.邮件的格式 抄送:需要知道这件事的人 内容: 大家好: 我是xxx,附件内容是我的简历,请查收,有问题可以随时联系我susun|开发工程师电话:1231xxxxx31地址:xxxxxx联系电话(公 ...
- 5个现在就该使用的数组Array方法: indexOf/filter/forEach/map/reduce详解(转)
ECMAScript5标准发布于2009年12月3日,它带来了一些新的,改善现有的Array数组操作的方法.然而,这些新奇的数组方法并没有真正流行起来的,因为当时市场上缺乏支持ES5的浏览器. ...
- 不用 qlv 格式转换成 mp4 - 优雅的下载腾讯视频(mp4 格式)
不用 qlv 格式转换成 mp4 - 优雅的下载腾讯视频(mp4 格式) 问题描述: 朋友说离线腾讯视频是 qlv 格式的,只能使用腾讯视频软件打开.让我帮忙想想办法,能不能将 qlv 格式转换成 m ...
- java小数保留位数四舍五入
方法一:四舍五入 double f = 111231.5585; BigDecimal b = new BigDecimal(f); double f1 = b.setScale(2, Roundin ...
- C#反射使用时注意BindingFlags的用法
c#反射查找方法时,默认只能查到public方法.如果想要查找private方法,需要设定BindingFlags. 即: BindingFlags.Public|BindingFlags.Insta ...
- 【转】JDK 内存参数含义
Eclipse崩溃,错误提示: MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) ...
- 【ubuntu】软件安装与apt-get下载软件的存放位置
系统:Ubuntu16.04 常用的软件安装方式有两种: 第一种:apt-get(安装后略类似于windows中的安装版软件): 例:apt-get install ssh 1.下载的软件存放位置 / ...