NanUI for Winform 使用示例【第二集】——作一個所見即所得的Markdown編輯器

【請注意:此文已過時,0.6版NanUI實現方式不一樣!!!】css

 

通過了這一個多星期的調整與修復,NanUI for .NET Winform的穩定版已經發布。應廣大羣友的要求,現已將NanUI的所有代碼開源。html

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

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

此次發佈的是一個相對穩定的版本,解決和改善了以下問題:git

  • 頁面隨機白屏問題(主要緣由是GC自動回收後,形成內存地址不可讀)
  • NanUI編譯版本改成.NET 4.0 Client Profile
  • 託上面那條改進的福,NanUI如今支持Windows XP
  • 再也不支持本地CEF運行支持文件,如今支持文件都須要在線下載安裝,固然也能夠手動下載離線包安裝,可是不論那種方式,CEF都安裝到一個共享的位置。CEF運行庫只需下載安裝一次,不會屢次下載。

歡迎下載把玩,也歡迎進羣討論,羣號241088256。github

下面,進入咱們的正題,使用NanUI以及手邊的各類開源庫製做一個所見即所得的Markdown編輯器。編程

NanUI系列目錄bootstrap

NanUI for Winform 使用示例【第二集】

作一個所見即所得的Markdown編輯器

在本集中,使用了以下開源技術來方便的組建咱們的「所見即所得Markdown編輯器」:後端

  • bootstrap
  • codeMirror
  • jquery
  • jquery.splitter.js
  • markdown-js
  • github-markdown.css

利用Nuget,獲取上列的各類庫不是難題。如效果圖所示,咱們能夠方便的利用這些開源庫來設計出心儀的頁面。在此着重講解網頁前端和後臺C#通訊的技術。後面的文章裏,凡是HTML、CSS和JS的內容我將稱他們爲「前端」、涉及C#編程的地方我會稱他們爲「後端」。微信

如圖所示,軟件將要與C#後端交互的幾個地方有:

  • 代碼編輯框
  • 新建文件按鈕
  • 打開文件按鈕
  • 保存文件按鈕

在C#後端,創建HostEditor類來處理由前端發送回來的按鈕事件。該類繼承自基類JSObject,這個類負責與CEF的V8環境處理各類數據和對象。

 1 class HostEditor:JSObject
 2 {
 3     frmMain MainFrame;
 4     internal HostEditor(frmMain main)
 5     {
 6         MainFrame = main;
 7 
 8         AddFunction("setCleanState").Execute += SetCleanState;
 9 
10         AddFunction("newFile").Execute += NewFile;
11 
12         AddFunction("openFile").Execute += OpenFile;
13 
14         AddFunction("saveFile").Execute += SaveFile;
15     }
16 
17     private void SaveFile(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
18     {
19         var contents = e.Arguments.FirstOrDefault(p => p.IsString);
20         var result = false;
21         if (contents != null)
22         {
23             result = MainFrame.SaveFile(contents.StringValue);
24 
25 
26         }
27 
28         if (result)
29         {
30             e.SetReturnValue(this.GetCfrObject(new
31             {
32                 success = true,
33                 fileName = MainFrame.CurrentFile.Name
34             }));
35         }
36         else
37         {
38             e.SetReturnValue(this.GetCfrObject(new
39             {
40                 success = false
41             }));
42         }
43     }
44 
45     private void OpenFile(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
46     {
47         var contents = e.Arguments.FirstOrDefault(p => p.IsString);
48         string result = null;
49         if (contents != null)
50         {
51             result = MainFrame.OpenFile(contents.StringValue);
52         }
53 
54         if (!string.IsNullOrEmpty(result))
55         {
56             e.SetReturnValue(this.GetCfrObject(new
57             {
58                 success = true,
59                 fileName = MainFrame.CurrentFile.Name,
60                 contents = result
61             }));
62 
63         }
64         else
65         {
66             e.SetReturnValue(this.GetCfrObject(new
67             {
68                 success = false
69             }));
70         }
71     }
72 
73     private void NewFile(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
74     {
75         var contents = e.Arguments.FirstOrDefault(p => p.IsString);
76         var result = false;
77         result = MainFrame.NewFile(contents.StringValue);
78 
79         e.SetReturnValue(CfrV8Value.CreateBool(result));
80     }
81 
82     private void SetCleanState(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
83     {
84         if(e.Arguments.Length>0 && e.Arguments[0].IsBool)
85         {
86             MainFrame.isClean = e.Arguments[0].BoolValue;
87         }
88     }
89 }

在主窗體的構造函數中,將上面的HostEditor類註冊到NanUI的JS環境中,並命名爲hostEditor,這樣在前端的JS中就能夠調用hostEditor對象以及對象中內置的C#方法了:

GlobalObject.Add("hostEditor", new HostEditor(this));

在JS環境中hostEditor對象提供瞭如下幾個方法來實現對當前代碼編輯器裏的內容進行新增、打開和保存的操做。

  • hostEditor.newFile(string)
  • hostEditor.openFile(string)
  • hostEditor.saveFile(string)
  • hostEditor.setCleanState(bool)

同時,將HostEditor中須要用到的新建文件、保存文件、打開文件等操做的方法放在主窗體中,方便前端JS調用。

        /// <summary>
        /// 標記文檔是否被修改
        /// </summary>
        internal bool isClean = true;
        /// <summary>
        /// 當前文檔的存儲路徑,若是爲空則說明該文檔是新文檔
        /// </summary>
        internal string currentFilePath = string.Empty;

        /// <summary>
        /// 當前文檔的FileInfo
        /// </summary>
        internal System.IO.FileInfo CurrentFile
        {
            get
            {
                return new System.IO.FileInfo(currentFilePath);
            }
        }

        /// <summary>
        /// 得到一個標識當前文檔是否爲新建文檔
        /// </summary>
        private bool IsNewFile
        {
            get
            {
                return string.IsNullOrEmpty(currentFilePath);
            }
        }
        /// <summary>
        /// 新建文件
        /// </summary>
        /// <param name="contents">當前文檔中的內容</param>
        /// <returns>若是新建成功則返回true</returns>
        internal bool NewFile(string contents)
        {
            var continueFlag = true;


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

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

            }

            if (!continueFlag)
            {
                return false;
            }

            currentFilePath = null;
            isClean = true;


            return true;
        }
        /// <summary>
        /// 打開文檔
        /// </summary>
        /// <param name="contents">當前文檔中的內容</param>
        /// <returns>若是新建成功則返回打開文檔的內容</returns>
        internal string OpenFile(string contents)
        {
            var continueFlag = true;
            if (!isClean)
            {
                var ret = MessageBox.Show(this, "文件已經更改,是否保存下先?", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

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

            }

            if (!continueFlag)
            {
                return null;
            }

            var content = string.Empty;

            var openDialog = new OpenFileDialog()
            {
                AddExtension = true,
                Filter = "Markdown文件|*.md"
            };

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

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

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

            }
            else
            {
                content = null;
            }

            return content;


        }
        /// <summary>
        /// 保存文檔
        /// </summary>
        /// <param name="contents">當前文檔中的內容</param>
        /// <returns>若是保存成功則返回true</returns>
        internal bool SaveFile(string contents) {

            if (!IsNewFile) {
                if (isClean) return true;


                System.IO.File.WriteAllText(currentFilePath, contents, Encoding.UTF8);
                isClean = true;
                return true;
            }


            var saveFileDialog = new SaveFileDialog()
            {
                AddExtension = true,
                Filter = "Markdown文件|*.md",
                OverwritePrompt = true
            };

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

                System.IO.File.WriteAllText(currentFilePath, contents, Encoding.UTF8);

                isClean = true;

                return true;
            }

            return false;

        }

 

如此這般,一個所見即所得的Markdown編輯器就製做完成了。有了這個小工具編輯GitHub的README文檔就不會那麼痛苦了。有興趣的朋友能夠自行到GitHub下載代碼來把玩。

那麼,NanUI的第二集示例就這麼講完了。最後仍是歡迎你們留言,或者進羣討論。固然能在github夠提供pull request是最好的。

 

附件

MarkdownDotNet.zip - 編譯好的Markdown編輯器,歡迎下載體驗,代碼已上傳到GitHub

 


NanUI for .NET Winform系列目錄


通過了這一個多星期的調整與修復,NanUI for .NET Winform的穩定版已經發布。應廣大羣友的要求,現已將NanUI的所有代碼開源。

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

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


 

 若是你喜歡NanUI項目,你能夠參與到NanUI的開發中來,固然你也能夠更直接了當的支持個人工做,使用支付寶或微信掃描下面二維碼請我喝一杯熱騰騰的咖啡。

支付寶轉帳

微信轉帳


 

另外,打個廣告,承接NanUI界面設計與接口開發(收費)。

案例展現

某聊天應用

某公司內部辦公系統

相關文章
相關標籤/搜索