科学技术NanUI for Winform 用示例【第一聚】——山寨个代码编辑器

NanUI for
Winform从昨天形容博客发布暨现取了同多朋友的体贴,首先感谢大家的关怀同支撑!请圈昨天自的博文《NanUI
for
Winform发布,让Winform界面设计拥有极可能》。

发心上人咨询到自身是否考虑开源NanUI,我想回答是迟早之。但是时来拘禁NanUI内部还有部分题材并不曾得到化解,因此少无见面绽放源代码。待这些问题顺利解决后我会第一时间把NanUI的源码放到GitHub,请稍等说话。

那么,从今天起我会陆续放出部分NanUI使用的片粗示例和源代码供感兴趣的情侣参考把嬉戏。任何有关NanUI的题目欢迎大家进群(群号:241088256)或留言及自我交流。

下,开始今天的以身作则

NanUI for Winform 以示例【第一聚众】

山寨个代码编辑器

科学技术 1

去年微软破天荒的发表了单吊炸天之开源代码编辑器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

科学技术 2

 

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

科学技术 3

去除掉用不着的文书,从品种面临祛或者直接删除都施行,剩下的得为此底型还在性质窗口被把转变操作改化“嵌入的资源”。然后新建个静态类,名字随便取,里面新建个方式来暴露资源类型的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的开发中来,当然你为堪重复直接了当的支持我之干活,使用支付宝还是微信扫描下二维码请自己喝相同盏热的咖啡。

科学技术 4

支付宝转账

科学技术 5

微信转发


 

除此以外,打只广告,承接NanUI界面设计与接口开发(收费)。

案例显示

有聊天应用

科学技术 6

有店里面办公室系统

科学技术 7

科学技术 8

Leave a Comment.