NanUI for Winform以示例[第一聚集]——山寨代码编辑器

NanUI for
Winform从昨天描绘博客发布暨今抱了跟多朋友的眷顾,首先感谢大家的关怀以及支撑!请看昨天自己的博文《NanUI
for
Winform发布,让Winform界面设计拥有极其可能》。

来对象问到自己是否考虑开源NanUI,我怀念回是必然之。但是当前来拘禁NanUI内部还有一部分题材并没有拿走化解,因此少无会见放源代码。待这些题材顺利解决后我会第一时间把NanUI的源码放到GitHub,请小等说话。

那么,从今天起我会陆续放出部分NanUI使用的有的小示例和源代码供感兴趣的朋友参考把打。任何有关NanUI的题材欢迎大家进群(群号:241088256)或留言与自我交流。

脚,开始今天的以身作则

NanUI for Winform 用示例【第一汇】

山寨个代码编辑器

去年微软破天荒的通告了个吊炸天的开源代码编辑器VS Code,观看VS
Code的目结构能,其实它们吗是依据CEF来进展开发的,使用的是名为electron的框架。那么,下面我以故NanUI山寨一个简约的Code编辑器实现对代码文件之新建、打开和封存操作,取名为NanUI代码编辑器。

NanUI代码编辑器使用的核心技术有:

  • Bootstrap
  • CodeMirror
  • NanUI for Winform(我理解,这句话是废话)
  • 从离别的资源程序集加载资源

Bootstrap做响应式的页面吊炸天,虽然咱今天如开展的小示例用不交响应式布局,但是引用进来就是当CSS
Clear用吧。另外一个CodeMirror作为网页端最精的代码编辑器,这次通过NanUI,我们的Winform也将分享它带动的强大力量。下面,我用分步讲解如何来山寨这个代码编辑器。

于VS中初建Windows
Application项目(后面称为主项目),然后以档次->属性->调试中关闭“启动VS承载进程”选项,因为经实践,开启该选择后无法加载嵌入的网页资源。同时,开启“启用本机代码调试选项”,因为ChromiumFX使用了PInvoke的法调用,会发出为数不少莫名其妙的非托管错误,例如,我事先便赶上个如开动项目就是报错的题材,开启了本机代码调试后意识凡是QQ拼音输入法钩子的题材,点个忽略继续就足以健康调试了。设置好后引用NanUI的库NetDimenison.NanUI.dll

 

再也新建一个类库项目(后面称为资源类),在里建立文件夹www,文件夹名字没要求,随意就吓,但要是强调一点,html文件未能够当类库项目的根目录下,必须树立个文本夹来放置网页文档。将bootstrap和codemirror的html、css和js文件等拷贝进www目录,当然你吗可以直接从nuget上下载它们,只是用拿nuget拿到之公文都拖到www里面,形成下面的文书结构。

删去掉用不着的文件,从种类蒙消除或者直接删除都推行,剩下的要为此的类还在性能窗口中管变化操作改成为“嵌入的资源”。然后新建个静态类,名字随便取,里面新建个点子来暴露资源路的Assembly。

namespace NanUI.Demo.CodeEditor.Resources
{
    public static class SchemeHelper
    {
        public static System.Reflection.Assembly GetSchemeAssembley()
        {
            return System.Reflection.Assembly.GetExecutingAssembly();
        }
    }
}

新建这个看似的作用是方便主项目登记资源类里的程序集,如果就此这种艺术来报资源文件需要在预告项目遭到援资源路。另外一个智,可以一直当主项目中直接动用Assembly.LoadFile加载资源类,如果项目要时更新的语句用者方式可形成时时更新资源文件要未用重新安装整个软件,具体的用法会在前的演示中介绍,在这就是非多说了。

这般,资源类型即使行好了。接下来的办事都拿当预告项目落得展开了。在预告项目的main函数里初始化NanUI。

namespace NanUI.Demo.CodeEditor
{
    using NetDimension.NanUI;

    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            UIStartupManager.UseSharedFramework = true;
            if (UIStartupManager.InitializeChromium())
            {
                //初始化成功,加载程序集内嵌的资源到运行时中
                UIStartupManager.RegisterEmbeddedScheme(Resources.SchemeHelper.GetSchemeAssembley());



                //启动主窗体
                Application.Run(new EditorForm());
            }


        }
    }
}

中,Resources.SchemeHelper.GetSchemeAssembley()方法就是是由资源类里把Assembly加载过来。之后新建编辑器的主窗体EditorForm。EditorForm除了简单的设置外,需另外上加几独主意来决定文件之新建、打开、保存等操作。

namespace NanUI.Demo.CodeEditor
{
    using NetDimension.NanUI;

    public partial class EditorForm : HtmlUIForm
    {

        internal bool isClean = true;
        internal bool isNew = true;

        internal string currentFilePath = string.Empty;


        public EditorForm()
            : base("embedded://www/main.html")
        {
            InitializeComponent();

            UI.GlobalObject.Add("hostEditor", new JsCodeEditorObject(this));
        }

        void SetEditorMode()
        {
            if (!string.IsNullOrEmpty(currentFilePath))
            {
                var fileInfo = new System.IO.FileInfo(currentFilePath);

                var ext = fileInfo.Extension;

                if (ext.IndexOf('.') == 0)
                {
                    ext = ext.Substring(1);
                    UI.ExecuteJavascript($"CodeEditor.changeCodeScheme('{ext}');");
                }
            }
        }

        //设置编辑器标题逻辑
        void SetEditorTitle()
        {
            if (isNew || string.IsNullOrEmpty(currentFilePath))
            {
                UI.ExecuteJavascript($"CodeEditor.setTitle('新建');");
            }
            else
            {
                var fileInfo = new System.IO.FileInfo(currentFilePath);
                UI.ExecuteJavascript($"CodeEditor.setTitle('{fileInfo.Name}');");
            }
        }
        //保存文件逻辑
        internal bool SaveFile()
        {
            var result = false;
            UI.EvaluateJavascript(@"CodeEditor.getContent()", (value, ex) =>
            {
                if (ex == null)
                {
                    var content = value.IsString ? value.StringValue : null;

                    if (content != null)
                    {

                        if (isNew)
                        {
                            var saveFileDialog = new SaveFileDialog()
                            {
                                AddExtension = true,
                                Filter = "支持的文件|*.txt;*.js;*.cs;*.html;*.htm;*.css;*.h;*.cpp;*.php;*.xml;*.vb",
                                OverwritePrompt = true
                            };
                            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
                            {
                                currentFilePath = saveFileDialog.FileName;
                                result = true;

                            }
                        }

                        if (result)
                        {
                            System.IO.File.WriteAllText(currentFilePath, content, Encoding.UTF8);
                            isClean = true;
                            SetEditorMode();
                            SetEditorTitle();
                        }



                    }
                }
            });

            return result;
        }
        //新建文件逻辑
        internal void NewFile()
        {
            var continueFlag = true;

            if (!isClean)
            {
                var ret = MessageBox.Show(this, "文件已经更改,是否保存下先?", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                if (ret == DialogResult.Yes)
                {
                    if (!SaveFile())
                    {
                        continueFlag = false;
                    }
                }
                else if (ret == DialogResult.Cancel)
                {
                    return;
                }
            }

            if (!continueFlag)
            {
                return;
            }

            isNew = true;
            isClean = true;


            UI.ExecuteJavascript(@"CodeEditor.setNew()");
            SetEditorTitle();



        }
        //打开文件逻辑
        internal string OpenFile()
        {
            var continueFlag = true;

            if (!isClean)
            {
                var ret = MessageBox.Show(this, "文件已经更改,是否保存下先?", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                if (ret == DialogResult.Yes)
                {
                    if (!SaveFile())
                    {
                        continueFlag = false;
                    }
                }
                else if (ret == DialogResult.Cancel)
                {
                    return null;
                }
            }

            if (!continueFlag)
            {
                return null;
            }

            var content = string.Empty;

            var openDialog = new OpenFileDialog()
            {
                AddExtension = true,
                Filter = "支持的文件|*.txt;*.js;*.cs;*.html;*.htm;*.css;*.h;*.cpp;*.php;*.xml;*.vb"
            };

            if (openDialog.ShowDialog() == DialogResult.OK)
            {
                currentFilePath = openDialog.FileName;

                var fileInfo = new System.IO.FileInfo(currentFilePath);

                content = System.IO.File.ReadAllText(fileInfo.FullName);

                isNew = false;

                SetEditorMode();
                SetEditorTitle();
            }
            else
            {
                content = null;
            }

            return content;
        }
    }
}

 

下面要来了,以下内容将涉及C#操作网页内JS代码以及JS调用C#的不二法门等等,核心就是是中间对象JsCodeEditorObject。该目标继承自ChromiumFX的JSObject对象,对JS有了解之心上人不见面针对JS的Object对象感到陌生,这里的JSObject对象和JS的Object对象实际大相像,也是带有了数据与道的一个聚集。如下所示,在里注册了大多单Function,这些Function都是能为网页端js调用的。

namespace NanUI.Demo.CodeEditor
{
    using Chromium.Remote;
    using NetDimension.NanUI;

    class JsCodeEditorObject : JSObject
    {

        EditorForm parentForm;

        internal JsCodeEditorObject(EditorForm parentForm)
        {
            this.parentForm = parentForm;

            AddFunction("newFile").Execute += JsCodeEditorObject_ExecuteNew;

            AddFunction("openFile").Execute += JsCodeEditorObject_ExecuteOpen;

            AddFunction("saveFile").Execute += JsCodeEditorObject_ExecuteSave;

            AddFunction("setClean").Execute += JsCodeEditorObject_ExecuteSetClean;
        }





        private void JsCodeEditorObject_ExecuteSetClean(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            if (e.Arguments.Length > 0)
            {

                parentForm.isClean = e.Arguments.First(p => p.IsBool).BoolValue;
            }
        }

        private void JsCodeEditorObject_ExecuteSave(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            var result  = parentForm.SaveFile();

            e.SetReturnValue(CfrV8Value.CreateBool(result));

        }

        private void JsCodeEditorObject_ExecuteOpen(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            var result = parentForm.OpenFile();

            if (result != null)
            {
                e.SetReturnValue(CfrV8Value.CreateString(result));

            }
            else
            {
                e.SetReturnValue(CfrV8Value.CreateNull());
            }
        }

        private void JsCodeEditorObject_ExecuteNew(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            parentForm.NewFile();
        }
    }
}

而上面代码中所展示的,这个类似注册了newFile, openFile,
saveFile和setClean几单主意供网页端js调用。再赔钱回来地方EditorForm的代码,有如此一行:

UI.GlobalObject.Add("hostEditor", new JsCodeEditorObject(this));

立马行代码的横便是将我们的中游对象JsCodeEditorObject实例化后传至浏览器的JS环境被,并且获得了单新名字叫“hostEditor”,这样,我们就算能以网页环境遭受之所以js执行下的几个方式了。

  • hostEditor.newFile
  • hostEditor.openFile
  • hostEditor.saveFile
  • hostEditor.setClean

当网页端js调用点这些方式的早晚实在会实行到EditorForm中相应的操作逻辑,如此就贯彻了js与c#条件之相。C#以及js环境相互和的比要简明得差不多,例如EdiorForm中的SetEditorTitle方法吃,通过UI.ExecuteJavascript方法就是可履web环境遭到之js代码或方式。

UI.ExecuteJavascript($"CodeEditor.setTitle('新建');");

假设达到这行代码,调用了js的艺术CodeEditor.setTitle来安编辑器的题目。那么,如果用实践js代码并回到相应代码,就得使UI.EvaluateJavascript方法。该办法第一个参数为js代码,第二单参数为施行js代码后底回调,它是一个发点儿独参数的action对象,第一单参数为回调的回到值,第二独参数是exception对象,如果js代码有问题,那么第二单对象exception就带有了错误信息,正确履行时,excepiton对象回来null。

UI.EvaluateJavascript(@"CodeEditor.getContent()", (value, ex) =>
{
    if (ex == null)
    {
        var content = value.IsString ? value.StringValue : null; //value对象是CfrV8Value对象,内置了各种数据转换的方法。

        //其他逻辑
    }
});

 

发矣上面的代码要点,大家该早就清楚C#暨JS之间的相方式以及JS于C#次的互的法门了。简而言之,C#与NanUI的js交互,无返回值的故UI.ExecuteJavascript方法,有返回值的用UI.EvaluateJavascript。除了这片个法子外,可以用UI.AddFunction方法来一直当js环境被注册C#的方法,方法大家自行钻研在此不再阐述。如果js需要跟C#中的交互,通过编制继承JSObject的中级对象注册方式还是数对象,即可兑现。

那,NanUI的以身作则第一集合就如此说得了了,如果未亮堂要留言为本人要进群(群号:241088256)交流,感谢大家关心。

 


NanUI for .NET Winform系列目录

  • NanUI for
    Winform发布,让Winform界面设计拥有极可能
  • NanUI for Winform
    用示例【第一集】——山寨个代码编辑器
  • NanUI for Winform
    以示例【第二聚众】——做一个所见就所得之Markdown编辑器

经过了就一个大多星期的调及修补,NanUI for .NET
Winform的风平浪静版曾宣布。应广大群友的渴求,现就将NanUI的周代码开源。

GitHub: https://github.com/NetDimension/NanUI

Release: https://github.com/NetDimension/NanUI/releases


 

 如果你欣赏NanUI项目,你可以与到NanUI的支付中来,当然你吗可以再直接了当的支撑我之做事,使用支付宝或者微信扫描下二维码请自己喝相同盏热的咖啡。

支付宝转账

微信转发


 

另外,打独广告,承接NanUI界面设计与接口开发(收费)。

案例显示

某个拉应用

某局里面办公室系统

相关文章