(C/C++)基于SharpUI控件库的插件式框架开发--第三篇框架基础服务库

  一个框架基础的东西,一般也是操作的最基础的类,比如char、int、bool等,有时出现内存泄露的问题导致错误的抛出,但是C++开发有的时候就算是抛出异常,那也是靠经验来积累才能非常快速准确的找出错误所在,这就需要在框架中需要添加日志管理的接口,日志管理的好处就是开发者自身在找异常时提供参考,另一个就是如果用户操作时出现问题,也可将日志反馈,帮助快速解决问题;总之了为了更好的扩展完善我的框架,我详细列一下这个基础服务库(XPCore)包含内容:

  • 虽说sharpui控件库内封闭好string类,但是不够满足需求,我就新定义了xstring类,这个字条串类中,涉及常用的所有操作,比如:查找、去空、大小写转换、取指定的字符串、连接、操作符运算、编码转换、与其他基础类间的转换、删除、替换等等;头文件如下:

      1 //xstring 常用编码格式
      2 enum XPCORE_API XEncodings
      3 {
      4     //默认编码
      5     encoding_gb2312=0,
      6     //wchar_t
      7     encoding_wchart=1,
      8     //Unicode
      9     encoding_unicode=2,
     10     //Unicode 的一种表达形式
     11     encoding_utf8=3
     12
     13 };
     14
     15 //自定义字符串类 xstring的最大长度
     16 #define _xstring_max_Length_ 4096
     17 //自定义字符串类 默认编码为GB2312,支持与Unicode wchar_t Utf-8转换
     18 class XPCORE_API xstring:implements XPCore::Object
     19 {
     20 public:
     21     xstring();
     22     xstring(const char* value);
     23     xstring(const wchar_t* value);
     24     xstring(const xstring &other);
     25     ~xstring();
     26
     27     const char* c_str() const;
     28     char* c_str();
     29
     30     const wchar_t* w_str() const;
     31     wchar_t* w_str();
     32
     33     int Lendth() const;
     34     bool Empty() const;
     35
     36     XEncodings Encoding() const;
     37     void SetEncoding(int encoding);
     38
     39     bool StartsWith(const xstring& value) const;
     40     bool EndsWith(const xstring& value) const;
     41     bool Contains(const xstring& value,int &startIndex) const;
     42     bool StartsWith(const char value) const;
     43     bool EndsWith(const char value) const;
     44     bool Contains(const char value,int &startIndex) const;
     45     bool Equals(const xstring& value) const;
     46
     47     static xstring FromInt(int value);
     48     static xstring FromFloat(float value,int numofDigits=10);
     49     static xstring FromBool(bool value);
     50
     51     int ToInt() const;
     52     float ToFloat() const;
     53     bool ToBool() const;
     54
     55     int IndexOf(char value, int startIndex) const;
     56     int IndexOf(const xstring& value) const;
     57     int IndexOf(const xstring& value, int startIndex) const;
     58     int IndexOf(char value, int startIndex, int count) const;
     59     int IndexOf(const xstring& value, int startIndex, int count) const;
     60
     61     bool Remove(int startIndex);
     62     bool Remove(int startIndex, int count);
     63     bool Replace(char oldChar, char newChar);
     64     bool Replace(const xstring& oldValue, const xstring& newValue);
     65
     66     xstring Insert(int startIndex, const xstring& insertValue);
     67
     68     xstring Substring(int startIndex) const;
     69     xstring Substring(int startIndex, int length) const;
     70     xstring Substring(int startIndex,int count, char sz) const;
     71
     72     xstring ToLower();
     73     xstring ToString();
     74     xstring ToUpper();
     75     xstring Trim();
     76     xstring TrimLeft();
     77     xstring TrimRight();
     78
     79     bool IsDigital() const;
     80     bool IsBool() const;
     81     bool IsCharacter() const;
     82
     83     void Clear();
     84
     85     char& operator[](int index);
     86     const char& operator[](int index) const;
     87
     88     xstring operator=(const xstring &other);
     89     xstring operator=(const char* val);
     90     xstring operator=(const wchar_t* val);
     91     xstring operator+(const xstring &other);
     92     void operator+=(const xstring &other);
     93     bool operator==(const xstring &other);
     94     bool operator>(const xstring &other);
     95     bool operator<(const xstring &other);
     96     /////////////////////////////////////////////////
     97
     98     static xstring FromUtf8(const xstring &other);
     99     static xstring FromUnicode(const xstring &other);
    100     static xstring FromGB2312(const xstring &other);
    101
    102     xstring ToUtf8();
    103     xstring ToUnicode();
    104     xstring ToGB2312();
    105 protected:
    106     char* _ptr;
    107     int _encoding;
    108 };

  • 内嵌了编码转换跨平台开源代码(Iconv,详细大家可以网上找对应资源),引用头文件“iconv.h”,定义共有方法:int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen),实现编码间转换,Iconv在转码方面还是很强大的,首先跨平台这优势就不言而喻了,其次方法简单,就只需要刚才定义的方法就可以如:xstring中定义的ToUtf8方法

    xstring xstring::ToUtf8()
    {
        char* _out=new char[_xstring_max_Length_];
        code_convert("GB2312","UTF-8",_ptr,strlen(_ptr),_out,_xstring_max_Length_);
        xstring _temStr=_out;
        _temStr.SetEncoding(XEncodings::encoding_utf8);
        return _temStr;
    }

  • 常用的宏,如类似接口的定义、释放内存等等

    //********************************************
    // Interface.h
    //主要是宏定义一些关键词,可以形成接口类
    //********************************************
    #ifndef _XPCOREINTERFACE_H
    #define _XPCOREINTERFACE_H  
    
    #define _Interface_ class
    //继承接口
    #define implements public
    
    //声明接口起始
    #define DeclareInterface(name) _Interface_ name { public:      virtual ~name() {}; 
    
    //声明带基类接口起始
    #define DeclareBasedInterface(name, base) _Interface_ name :     public base{ public:         virtual ~name() {};
    //#ifdef FRAMEWORKCORE_EXPORTS
    //声明带输出接口起始
    #define DeclareAPIInterface(name) \
        _Interface_ name { public:     virtual ~name() {}; 
    
    //声明带基类带输出接口起始
    #define DeclareBasedAPIInterface(name, base) _Interface_  name : public base {     public:         virtual ~name() {};
    //声明带基类带输出接口起始
    #define DeclareBasedAPIInterface2(name, base1,base2) _Interface_  name :     public base1,public base2 { public:     virtual ~name() {};
    //声明带基类带输出接口起始
    #define DeclareBasedAPIInterface3(name, base1,base2,base3) _Interface_  name :     public base1,public base2 ,public base3{ public:     virtual ~name() {}; 
    
    //声明接口结束
    #define EndInterface };

  • 另外为了能唯一标识某些类或标识添加的一个按钮,这就需要GUID;但是为了能灵活用GUID,这里也定义了下GUIDHelper

    class XPCORE_API GuidHelper
    
    {
    public:
        static const GUID NewGUID();
        static const char* GUIDToChar(const GUID &guid);
        static bool CharToGUID(const char* str,GUID &guid);
    
    };
    //新建GUID
    #define _NEW_GUID_ GuidHelper::NewGUID()
    
    //源
    const GUID GuidHelper::NewGUID()
    {
        GUID guid;
        #ifdef WIN32
            CoCreateGuid(&guid);
        #else
            uuid_generate(reinterpret_cast<unsigned char *>(&guid));
        #endif
        return guid;
    }
    
    const char* GuidHelper::GUIDToChar(const GUID &guid)
    {
        char buf[128] = {0};
        #ifdef __GNUC__
            snprintf(
        #else // MSVC
            _snprintf_s(
        #endif
        buf,
        sizeof(buf),
            "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
        guid.Data1, guid.Data2, guid.Data3,
        guid.Data4[0], guid.Data4[1],
        guid.Data4[2], guid.Data4[3],
        guid.Data4[4], guid.Data4[5],
        guid.Data4[6], guid.Data4[7]);
        return buf;
    }
    
    bool GuidHelper::CharToGUID(const char* str,GUID &guid)
    {
        memset(&guid, 0, sizeof(GUID));
        int nRet=sscanf_s(
        str,
        "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
        &(guid.Data1),
        &(guid.Data2),
        &(guid.Data3),
        &(guid.Data4[0]),
        &(guid.Data4[1]),
        &(guid.Data4[2]),
        &(guid.Data4[3]),
        &(guid.Data4[4]),
        &(guid.Data4[5]),
        &(guid.Data4[6]),
        &(guid.Data4[7])
        );
        return (nRet == 11)? true : false ;
    }

  • 因为是插件式管理框架,所以需要定义每个插件对应的配置,这里选择用LUA角本语言来定义插件配置,因此,在这个库里也内嵌了LUA的源代码,不过只用到了一种方法就是将定义好的C++类绑定到Lua角本编译器的虚拟机中,实现对配置信息的读入和加载

    //单个插件 struct
    typedef struct tagPluginInfo
    {
        char name[MAX_PATH];
        char url[MAX_PATH];
        char description[MAX_PATH];
        char author[MAX_PATH];
        bool isHiddenInManager;
        bool isLoadAutoStart;
        bool isUnload;
    }_pluginInfo,*P_pluginInfo;
    
    //单个插件
    class XPCORE_API plugin:implements XPCore::Object
    {
    public:
        plugin();
        plugin(plugin &other);
        plugin(_pluginInfo &other);
        ~plugin();
    
    public://插件描述信息
        char* GetName();
        void SetName(const char* val);
    
        char* GetAuthor();
        void SetAuthor(const char* val);
    
        char* GetURL();
        void SetURL(const char* val);
    
        char* GetDescription();
        void SetDescription(const char* des);
    
        bool IsHiddenInManager();
        void SetIsHiddenInManager(bool val);
    
        bool IsLoadAutoStart();
        void SetIsLoadAutoStart(bool val);
    
        bool IsUnload();
        void SetIsUnload(bool val);
    
    protected:
        char name[MAX_PATH];
        char url[MAX_PATH];
        char description[MAX_PATH];
        char author[MAX_PATH];
        bool isHiddenInManager;
        bool isLoadAutoStart;
        bool isUnload;
    
    public:
        VectorArray<pluginItem> Items;
    
    };
    
    //Lua角本中编写
    local pin=plugin.create() --初始化插件
    plugin.setName(pin,"Base")--设置插件名
    plugin.setAuthor(pin,"Xp.W")--设置插件作者
    plugin.setUrl(pin,"http://www.ruitesen.com")--设置插件网址
    plugin.setDescription(pin,"基础插件,构建了基本的菜单项和工具条,该插件不可卸载。")--设置插件描述
    plugin.setIsHiddenInManager(pin,false)--设置插件是否插件管理中隐藏
    plugin.setIsLoadAutoStart(pin,true)--设置插件是否有自启动项
    --插件中的控件集合,注意这里的集合名必须与c项目中一致
    --集合中的每一项的索引标识固定,且顺序固定,更改会导致异常
    --plugin.addItem(pin,"[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@conditioName")
    --添加一级菜单 类型有:Menu  MenuCommand  CheckMenuCommand MenuSeparator
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    --添加二级菜单
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected][email protected]@MapOpenedConditionEvaluator")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    --添加默认工具条
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]")
    --添加工具条按钮  类型有:Button  ToggleButton SplitButton DropdownButton RadioButton CheckBox ComboBox TextBox TextBlock ToolbarSeparator
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected][email protected]@MapOpenedConditionEvaluator")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected][email protected]@[email protected][email protected]@MapOpenedConditionEvaluator")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@conditioName")
    plugin.addItem(pin,"[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@conditioName")
    plugin.load(pin)--导入到插件管理

  • 同样的插件式管理框架也需要对dll的动态加载和函数获取

    // dll库管理类
    class XPCORE_API DLLManager
    {
    public:
        DLLManager();
        virtual ~DLLManager(void){FreeALLDll();}
        //注册Dll库
        bool AddDll(char* dllFileName);
        //是否包含对应GUID的Dl库
        bool ContainsDll(char* dllFileName);
        //是否包含对应GUID的Dl库,并返回对应索引
        bool ContainsDll(char* dllFileName,int &index);
        //反注册Dll库,释放对应内存
        bool FreeDll(char* dllFileName);
        //获取对应GUID的dll模块
        HMODULE &GetMoudle(char* dllFileName);
        HMODULE &GetMoudle(const int index);
        //反注册所有Dll库,释放对应内存
        void FreeALLDll();
    
    protected:
        VectorDic<char*,HMODULE> _modeules;
    
    };
    //DllMAnager 源
    
    DLLManager::DLLManager()
    {
    
    }
    
    bool DLLManager::AddDll(char* dllFileName)
    {
        HMODULE hModule;
        if(!ContainsDll(dllFileName))
        {
    #ifdef UNICODE
            wchar_t fileName[MAX_PATH];
            wchar_t* _fileName=fileName;
            CharToUnicode(dllFileName,_fileName);
            hModule=::LoadLibrary(_fileName);
    #else
            char _fileName[MAX_PATH];
            strcpy(_fileName,dllFileName);
            hModule=::LoadLibrary(_fileName);
    #endif
            _modeules.Add(dllFileName,hModule);
            return true;
        }
        return false;
    }
    
    bool DLLManager::ContainsDll(char* dllFileName)
    {
        return _modeules.ContainsKey(dllFileName);
    }
    
    bool DLLManager::ContainsDll(char* dllFileName,int &index)
    {
        return _modeules.ContainsKey(dllFileName,index);
    }
    
    bool DLLManager::FreeDll(char* dllFileName)
    {
        int index=0;
        if(_modeules.ContainsKey(dllFileName,index))
        {
            ::FreeLibrary(_modeules.GetValue(index));
            _modeules.RemoveAt(index);
            return true;
        }
        return false;
    }
    
    HMODULE &DLLManager::GetMoudle(char* dllFileName)
    {
        int index=0;
        if(_modeules.ContainsKey(dllFileName,index))
        {
            return _modeules.GetValue(index);
        }
        HMODULE _nullModule;
        return _nullModule;
    }
    
    HMODULE &DLLManager::GetMoudle(const int index)
    {
        if(_modeules.Count()>index && index>-1)
        {
            return _modeules.GetValue(index);
        }
        HMODULE _nullModule;
        return _nullModule;
    }
    
    void DLLManager::FreeALLDll()
    {
        for(int i=0;i<_modeules.Count();i++)
        {
            ::FreeLibrary(_modeules.GetValue(i));
        }
        _modeules.Clear();
    }
    
    //函数获取类  模板定义
    //从指定的DLL模块中实例化对应对象的指针
    template<typename T>
    T *GetPtrFromMoudle(HMODULE &moudle,const char *moudleName)
    {
        return (T*)::GetProcAddress(moudle,moudleName);
    }
    
    template<typename T>
    T GetObjFromMoudle(HMODULE &moudle,const char *moudleName)
    {
        return (T)::GetProcAddress(moudle,moudleName);
    }
     

  • 资源的管理

    class XPCORE_API ResourceService
    {
    public:
        //获取字符资源从资源字典(返回的为字符串的转换名或Imge的全路径)
        static char *ParseStringFormDic(char *val);
        //获取命令从资源字典
        static XPCore::ICommand* ParseCommandFromDic(char *val);
        //获取条件命令从资源字典
        static XPCore::IConditionEvaluator* ParseConditionEvaluatorFromDic(char *val);
    };

  • 基本命令接口,用于绑定到控件触发事件中

    namespace XPCore
    {
        /// <summary>
        /// A basic command interface. A command has simply an owner which "runs" the command
        /// and a Run method which invokes the command.
        /// </summary>
        DeclareBasedAPIInterface(ICommand,XPCore::Object)
    
            virtual bool IsEnabled()=0;
            virtual void SetIsEabled(bool val){};
    
            virtual XPCore::Object* Owner()=0;
            virtual void SetOwner(XPCore::Object *val){};
    
            virtual void OnOwnerChanged(){};
    
            virtual void Run(){};
    
        EndInterface
    
        /// <summary>
        /// A basic checked command interface. A command has simply an owner which "runs" the command
        /// and a Run method which invokes the command.
        /// </summary>
        DeclareBasedAPIInterface(ICheckedCommand,XPCore::ICommand)
    
            virtual bool IsChecked()=0;
            virtual void SetIsChecked(bool val){};
    
        EndInterface
    
    }

  • 基本条件命令接口,用于返回需要对控件状态刷新的条件操作动作
    //条件执行动作
    enum XPCORE_API ConditionAction
    {
        //非激活
        disable_action,
        //隐藏
        hide_action,
        //无
        null_action
    };

    namespace XPCore
    {
        /// <summary>
        /// ConditionEvaluator
        /// </summary>
        DeclareBasedAPIInterface(IConditionEvaluator,XPCore::Object)
    
            //返回值 为枚举型的整数值
            virtual int ConditionEvaluator()=0;
    
        EndInterface
    }

    以上基本就是基础服务库中的全部内容,当然由于篇幅原因,并没有将全部代码贴出来;

  写到这,相信应该明白为什么要写这个库了,这是这个插件式框架的基石,有了它我就可以扩展了:这个插件式框架的主要思想就是:框架的开发与插件的开发要完全独立,插件间也要完全独立,框架要能实现动态加载插件中定义的方法和界面的对应的资源加载,所以用LUA角本定义配置信息,插件Dll开放指定两个方法:AutoStart(加载命令和条件绑定资源)和LoadStringResource(加载字符和图标资源)两个方法就可以,具体调用可以上面提到的DLLManager,来调用定两个方法,实现资源加载,动态生成控件和根据绑定条件刷新状态,所有的绑定都是通过字符串来实现。

  最后赋上运行图片(主界面和插件管理界面),下一篇将写一下如何基于SharpUI编写一个自己要想的控件(以插件管理器中的导航面版为例):

界面中所有菜单和工具按钮全是通过Base插件中自动生成。

本文版权所有,如转发和引用请注明。

时间: 2024-10-12 15:45:05

(C/C++)基于SharpUI控件库的插件式框架开发--第三篇框架基础服务库的相关文章

(C/C++)基于SharpUI控件库的插件式框架开发--第一篇简介

看到题目,很明显这里要说的是插件式框架的开发,当然是用c/c++来实现的.开发对于我来说,是一种爱好,但并非科班出身,所以这里要说的一点分享就是,开发并不是会写代码就行了,最主要的是要有思路想法,比如要实现一个功能,就要知道,这个功能到底是要来实现啥的,要实现它需要什么样的算法等等,做到胸中有丘壑,再去用最简单代码去实现它,就会发现写代码是一件很享受的事情. 参加工作快两年了,一开始的是用C#开发,写了半年多的功能和小控件,上手之后,参考ICSharpCode.Core.Presentation

(C/C++)基于SharpUI控件库的插件式框架开发--第二篇可停靠管理

一个软件,不可能只有一个文档界面,会有多个甚至几十二,比如一些浏览器.文档查看等都是多个标签页的形式,在C#中开源的可停靠管理的常用的是Xceed.Wpf.AvalonDock:但是用C/C++开发的开源停靠管理库是没找到,没办法只能自己写一个了. 图1 可停靠管理项目名XPDock,其中所有控件的样式存放在“.bin\layout\Theme\Controls\XPDock.xml”:如图2: 图2 在XPDock控件中,DockingManager为控件主要控件,控件内定义添加视图方法Add

用户控件的缓存技术之二【共三篇】

原文发布时间为:2009-10-29 -- 来源于本人的百度文章 [由搬家工具导入] ASP.NET 缓存功能是一项很重要的功能,而这其中使用最多的就是利用用户控件实现的片段缓存。有时候,缓存整个页是不实际的;可能需要为每个请求动态创建页的某些部分。在这些情况下,您可能值得花时间来标识与需要大量的服务器资源来构造的页请求相关联的对象或数据。一旦标识了这些项,您就可以通过在 Web 窗体用户控件中创建这些项将它们从页的其他部分分离出来,然后在一段指定的时间中对这些项进行缓存,以节省服务器资源。这就

Vue.js 自定义组件封装实录——基于现有控件的二次封装(以计时器为例)

在本人着手开发一个考试系统的过程中,出现了如下一个需求:制作一个倒计时的控件显示在试卷页面上.本文所记录的就是这样的一个过程. 前期工作 对于这个需求,自然我想到的是有没有现成的组件可以直接使用(本着不重复发明轮子的原则).于是我就在 GitHub 上找寻.确实找到了不少,但是与需求之间的差距还比较大.从零开始写又不太现实(时间摆在那里,加之自己的前端也是刚学,还没有从零开始手撸一个控件的能力),所以在已有组件的基础上进行二次封装便成了一个比较可行的方法(几乎也是唯一解).遂在 npm 上以 c

扩展ToolBarManager、ListView和Grid控件以实现气球式的ToolTip

原文:扩展ToolBarManager.ListView和Grid控件以实现气球式的ToolTip infragistics是全球领先的UI工具和用户体验的专家,Infragistics开发了一系列的炫目的Windows.Web.WPF和Silverlight控件,相信很多人在使用它们.我们现在的项目就在使用Infragistics的Windows Form控件集.虽然这些控件功能强大,也不可能满足你所有的需求,尤其是那些比较苛刻的最终用户的需求.比如,我们最近就接收到这样一个变态的需求:让所以

Baseline Testing 开源(基于Python插件式结构开发)

[其他]入职37.com后写的一个东西,为了检查下服务器的一些安全配置.数量太多,手工不靠谱. [OSCHINA开源社区地址]http://www.oschina.net/p/baseline-testing 基于Linux的配置检查工具,采用插件式结构开发.开发语言使用的是python.开发者可以通过自行开发插件来扩展该工具,灵活性高.开发该工具的主要目的是因为刚入职,需要对几百台服务器进行检查.有需要的朋友可以对其进行插件扩展.在使用的过程当中,可以自己配置FTP,目前支持将结果上传到FTP

基于Treeview控件遍历本地磁盘

一.前言 Treeview控件常用于遍历本地文件信息,通常与Datagridview与ImageList搭配.ImageList控件用于提供小图片给TreeView控件,DatagridView通常显示TreeNode节点下文件及文件夹的信息. 效果图:       二.代码 初始化窗体: private void ManagerForm_Load(object sender, EventArgs e) { InitialDataGridView(dgv_Local); //初始化本地dgv I

一个字体,大小,颜色可定义的自绘静态框控件-XColorStatic 类(比较好看,一共19篇自绘文章)

翻译来源:https://www.codeproject.com/Articles/5242/XColorStatic-a-colorizing-static-control XColor Static是一个简单的基于静态框的控件,它提供字体更改,文本和背景颜色以及图标显示. 下载演示项目 - 32.2 Kb 介绍 XColor Static是一种通用控件,允许在对话框中显示漂亮的文本.该演示向您展示了可能的文本和图标显示类型: XColorstatic API 以下是完整的方法列表:CXCol

使用Aspose.Cell控件实现Excel高难度报表的生成(三)

在之前几篇文章中,介绍了关于Apsose.cell这个强大的Excel操作控件的使用,相关文章如下: 使用Aspose.Cell控件实现Excel高难度报表的生成(一) 使用Aspose.Cell控件实现Excel高难度报表的生成(二) 使用Aspose.Cell控件实现多个Excel文件的合并 这几篇文章,都对Apose.Cell这个控件生成各种Excel的方式进行了阐述,对直接把DataTable或者IList生成Excel的操作,对通过模板方式实现自定义报表的各种方式,以及多个文件的合并的