Visual WebGUI Custom Control

上次講咗直接用 HtmlBox run Xonomy(一個建基於 jQuery 的 XML editor),今次就係講掂樣將佢整做 Custom Control,整成 Custom Control 嘅好處多多,例如可以將喲 css/ js/images/html  都做成 embedded 檔案,唔使担心裝漏咗,又或者錯咗版本。不過,你需要識嘅嘢就多喲,睇落高檔啲,實際都係 pro 啲嘅,如果學有所成,日後要喺 Visual WebGUI 入面用 jQuery 的 plugins 就易好多!

首先,用 VS2010 開一個新嘅吉嘅 solution,solution 名係 VWG.Community,加第一隻 project,project type 要選做 Visual WebGUI Library,而 project 名就叫 VWG.Community.Forms ,咁,日後有第 2 第 3 隻 Custom Controls 都可以放喺同一個 project 入面。 delete 咗 create new project 時候 VS2010 佢送嘅 UserControl1.cs,再 add 一個 new item Visual WebGUI Custom Control ,個名用 XonomyBox,我哋以後就叫哩個 Custom  Control 做 XonomyBox,個 Assembly name 就係 VWG.Community.Forms.XonomyBox,完成嘅話就會好似下面張圖咁:

Screen Shot 2016-02-23 at 10.06.33 AM

VS2010 又送咗一堆 default codes,將冇用嘅 delete 或者 remark 咗:

Screen Shot 2016-02-23 at 10.11.22 AM

要解釋下啲 code:


namespace VWG.Community.Forms
{
  /// <summary>
  /// Summary description for XonomyBox
  /// </summary>
  [ToolboxItem(true)]
  //[ToolboxBitmapAttribute(typeof(XonomyBox), "VWG.Community.Forms.XonomyBox.bmp")]
  //[DesignTimeController("Gizmox.WebGUI.Forms.Design.PlaceHolderController, Gizmox.WebGUI.Forms.Design, Version=4.0.5701.0 , Culture=neutral, PublicKeyToken=dd2a1fd4d120c769")]
  //[ClientController("Gizmox.WebGUI.Client.Controllers.PlaceHolderController, Gizmox.WebGUI.Client, Version=4.0.5701.0 , Culture=neutral, PublicKeyToken=0fb8f99bd6cd7e23")]
  [Serializable()]
  //[MetadataTag("VWG.Community.Forms.XonomyBox")]
  [Skin(typeof(XonomyBoxSkin))]
  public partial class XonomyBox : HtmlBox
  {
    public XonomyBox()
  {

    InitializeComponent();
  }

  protected override void RenderAttributes(IContext context, IAttributeWriter writer)
  {
    base.RenderAttributes(context, writer);

    writer.WriteAttributeString(WGAttributes.Text, Text);
  }
}

line 7 comment out,因為冇用,我唔鍾意用 desinger 嚟 create 啲 web page controls,因為早期嘅 Visual WebGUI designer 有好多 bug,而且 upgrade 嘅時候仲麻煩多多,我習慣盡量少用 designer,況且係隻 icon,一啲都唔重要。

line 8 & 9 comment out,又係無關重要,如果真係要寫,就應該搞埋其它 Visual WebGUI 版本,可以參考 CKEditor 入面嘅 code。

line 11 comment out 就連我都唔明,因為 Visual WebGUI 教你,咁做可以建立一個新嘅 MetadataTag 俾哩隻 Custom Control 專用,咁即係好應該採用咖,不過我就一用親專用嘅 Tag 隻 XonomyBox 就 load 唔倒入個 web page,即係,啲 code 就照 run,不過就冇畫面,好似 Visual WebGUI engine 搵唔倒隻 user control 咁,唯有暫一直 comment out 啦,要等高手,可惜 Visual WebGUI v6.4 嘅時候由 free 改為收費,而且仲收得幾貴添,於是走咗一班勁網友,最近 v10.0 又話免費番,不過冇咩人返嚟,最近個 v10.0.5 又想收番錢,轉來轉去,一啲都唔專業,而且一個星期內出到 v10.0.5e,bug 到七彩,啲 quality control 同以前差不多,醫得頭來腳板痛,除咗啲鐡杆粉絲邊有人俾呀。

line 13 inherite 由 Control 轉為 HtmlBox,HtmlBox 由 FrameControl 嚟,本來我哋可以 inherite FrameControl 嘅,不過唔好搞到咁複雜,就用 HtmlBox 啦,於是 XonomyBoxSkin 都要相應改一改:

 

Screen Shot 2016-02-23 at 10.12.09 AM

到此為止,build 一下,睇下有冇 bug,有冇打錯字,而且唔 build 一嘢,Visual Studio edit 唔倒隻 XonomyBoxSkin.cs,打開嘅時候會出 designer exceptional error。

right click XonomyBoxSkin.cs 選 View Designer:

Screen Shot 2016-02-23 at 10.13.25 AM

開始 embed Xonomy 要用嘅檔案,先加 image files:

Screen Shot 2016-02-23 at 10.15.06 AM

將 Xonomy 下載返嚟嘅 images 加哂落去:

Screen Shot 2016-02-23 at 10.15.54 AM

加 Style file xonomy.css,加 Script file xonomy.js,Add new Html 叫 XonomyBox.html ,噢,add new 唔俾你打個名,你要用 add new + rename(你唔使打 .html,會自動加俾你),再 Add new Script 叫 XonomyBox.js。打開 XonomyBox.js,空白一片,加 code:

Screen Shot 2016-02-23 at 10.20.01 AM

又嚟解釋下啲 code:

function start(sUrlXml, sUrlSpec) {
  if (!sUrlXml) sUrlXml = getParameterByName("xml"); // 如果 caller 冇提供 sUrlXmls 同 UrlSpec,就去 QueryString 搵
  if (!sUrlSpec) sUrlSpec = getParameterByName("spec");

  var editor = document.getElementById("editor");

  $.ajax({ url: sUrlXml, dataType: 'xml', type: 'GET', // sUrlXml 係 XMLDocument
    error: function () {
      alert("failed to load xml file");
    },
    success: function (xmlFile) {
      $.ajax({ url: sUrlSpec, dataType: 'script', type: 'GET', // sUrlSpec 係 javascript
        error: function () {
          //no doc spec, read only
          Xonomy.render(xmlFile, editor, "null");
        },
        success: function (docFile) {
          Xonomy.render(xmlFile, editor, docSpec); // 這裡的 docSpec 係隱藏在 docFile 中
        }
      });
    }
  });
}

function start 嘅作用係 讀入 隻 XML Data 同埋隻 DocSpec,然後 initialize Xonomy,兩隻檔案可以由 caller 提供兩個 parameters,如果冇提供就自己去 QueryString 搵。因為我搞唔掂 Data_GetAttribtue 所以依家係用 QueryString。

line 2 & 3 就係咁嘅意思,getParameterByName 會去 QueryString 搵兩隻 parameters (兩隻檔案嘅 http url)。

line 7 $.ajax 係 jQuery function 讀入 XML Document 檔案,有 error 就報錯,終止。如果冇錯,就 return XML Document object (xmlFile)。

line 12 同一個 jQuery function 唔同 parameter dataType,讀入 DocSpec javascript 檔案,有 error 就當係 read only,冇,就准更改隻 Xml Data。


function harvest(formId) {
  if (typeof (VWG) == 'undefined' || VWG == null || VWG.Events == null) return;
  var xml = Xonomy.harvest();
  var eventType = "XonomyHarvest";
  var objEvent = VWG.Events.CreateEvent(formId, eventType);
  VWG.Events.SetEventAttribute(objEvent, "Value", xml);
  VWG.Events.RaiseEvents();
}

function harvest 會 call Xonomy.harvest(),將最 recent 嘅 xml data 放入 variable xml, 再 callback server(RaiseEvents),line 6 嘅 “Value” 係 key name,你可以叫唔同嘅名,不過要同 server 個 FireEvent match,key value 就係 variable xml。

line 1 嘅 formId 好重要,唔錯得,因為  Visual WebGUI 會用嚟記住係哩個 control 叫 postback,而且 HtmlBox 喺 client side 係 iFrame 嚟,iFrame 入面啲 html elements 可以自成一國,所以 formId 會由 server invoke 個 event 時候提供,減少麻煩!

function showAttribute 係用嚟測試 Data_GetAttribute work 唔 work,我就搞唔掂,trace 落去,DataRootObject 唔知掂解長期係 null,冇得搞,行人止步。

function getParameterByName 係普通 javascript,去 QueryString 搵你要嘅 parameter,抄人哋嘅,冇咩特別。 🙂

輪到 edit XonomyBox.html,XonomyBox.html 唔係吉嘅,VS2010 送咗幾句 standard code 俾你,唔使理,改為:

Screen Shot 2016-02-23 at 10.21.49 AM.png

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" lang="Context.Language">
<head>
<title>XonomyBox Page</title>
  <script type="text/javascript" src="Resources.Includes.js.wgx"></script&amp;amp;gt;>
  <script type="text/javascript" src="Resources.Browser.Form.js.wgx"></script>
  <script type="text/javascript" src="Resources.Gizmox.WebGUI.Forms.Skins.CommonSkin.Interfaces.js.wgx"></script>
  <script type="text/javascript" src="[Skin.Path]xonomy.js.wgx"></script>
  <script type="text/javascript" src="[Skin.Path]XonomyBox.js.wgx"></script>
  <link type="text/css" rel="stylesheet" href="[Skin.Path]xonomy.css.wgx"/>
</head>
<body onload="start()">
  <div id="editor"></div>
</body>
</html>

line 5, 6 & 7 係 include Visual WebGUI client API,可以用 VWG 嘅 object RaiseEvents 做 postback,同埋可以用 VWG embed 嘅 jQuery,唔使為 Xonomy 再 include 一個 jQuery javascript file,多隻香爐多隻鬼,除非要用唔同嘅 jQuery version 否則唔好搞多件。

line 8,9 &10 都有 [Skin.Path] VWG 解讀嘅時候會轉換成 embedded resources 嘅 url gateway。

line 12,當 web page loaded 之後就 call start() 去啟動 (initialize) Xonomy。

line13,div id=editor 係俾 Xonomy 用嘅,隻 xml editor 就放喺哩度。

主菜上場(XonomyBox.cs):

Screen Shot 2016-02-23 at 7.31.59 PM

  • public XonomyBox()  有 overloading
  • RenderAttribute 留有測試 Data_GetAttribute 啲 codes,你可以去試試,掂咗嘅話,可以教下我
  • FireEvent 會 detect caller,如果係 XonomyHarvest 就會 call SaveHarvest() 將 edit 咗嘅  xml data save 入 disk file。講多句,FireEvent 完咗,VWG HtmlBox 會自動再 reload 個 web page,onload=restart() 又會 run 一嘢,即係,如果,我係話如果,你冇利用 SaveHarvest() 更新隻 disk file,你 edit 完之後 click Harvest,係就係 harvest 咗,不過你最後又係會見到舊嘅未改嘅 xml data。應該叫 HtmlBox 唔好去 reload,不過我就唔識,唯有哪哪聲去 update 個 disk file,咁,reload 之後會睇到新嘢。
  • Harvest() 會 call client side 叫 client 指示 Xonomy 將最新嘅 xml data 送返嚟 server
  • protected override String Source 係 VWG 指定嘅 Attribute,會將 embedded 嘅 XonomyBox.html url gateway 放入 HtmlBox 內,用咗 Source 就唔使用 HtmlBox.Url 或 HtmlBox.Html attribute

好嘞,搞完內容,要搞搞 VWG 嘅 obscuring:

Screen Shot 2016-02-23 at 10.33.49 AM

VWG 會將 send 去 client 嘅資料加 obscuring,obscuring 即係將啲 html 呀 javascript 呀 亂寫一通,等你用 browser developer tools 都睇唔明,唔識搞破壞,係保安問題,同埋減少 client 同 server 之間嘅 traffic。不過,VWG 會有特定嘅要求,例如所有 javascrip functions 要加 XonomyBox_ 在前,我加嗰幾句仲可以改一下,xonomy.js 入面嘅 functions 就比較麻煩,我決定唔用 obscuring,而且 debug 嘅時候都比較易。 🙂

喺 XonomyBoxSkin 入面嘅 css/ js/ html 都要把 CompilerActions 改成 None(uncheck 所有):

Screen Shot 2016-02-23 at 10.34.03 AM

Screen Shot 2016-02-23 at 10.34.28 AM

最後就係改一下 xonomy.css 內 reference images 的地方,在前面加上 [Skin.Path],後面加上 .wgx,為咩?咪講過囉,因為 VWG 個 Url Gateway 係要咁先可以將啲 embedded files 發俾 client:

Screen Shot 2016-02-23 at 7.25.06 PM

完哂,所有 project files 喺哩度下載,入面有埋一個 test project,我係用 VS2010 VisualWebGUI v10.0.5e 嘅。