開發自己的Windows Live Writer插件

[標題]: 開發自己的Windows Live Writer插件
[時間]:2009-10-04
[摘要]: 開發一個Windows Live Writer插件,在寫博客時,添加自己的代碼樣式。最終效果是,在Windows Live Writer中選中代碼,然後點擊插件,將代碼包含在<div class="mycode">your code</div>中。
[關鍵字]: plugin、Windows Live Writer、code、format、highlight、 插件、博客、blog、msi、package、打包、C#
[環境]: Windows Live Writer 14.0.8089.726 zh-cn, Visual Studio 2008 , Windows XP SP3 , Wordpress 2.8.4
[作者]:Winty  ([email protected]
[正文]:
         開發一個Windows Live Writer插件,在寫博客時,添加自己的代碼樣式。最終效果是,在Windows Live Writer中選中代碼,然後點擊插件,將代碼包含在<div class="mycode">your code</div>中。當然要在最終發表的博客上添加.mycode 的CSS樣式纔有效果。
        .mycode樣式如下:
.mycode {
    margin: 10px;
    padding: 10px;
    background: #DDEDFB;
    border: 1px solid #428EDE; 
    text-align: left;
    /*width:500px;*/
    overflow-x:auto;
    font-size:20px;
    white-space:nowrap;
    *white-space: normal;
    WORD-WRAP: break-word;/*IE*/
    word-break:break-all;/*IE*/
}
選中代碼,點擊"WintyCodeArea":
  
效果如下圖
(在Writer需啓用"使用主題編輯",並已從博客中獲取主題,才能立即看到效果):
 
 

0、準備工作

  • 在Visual Studio 2008中新建C#"Class Library"項目
  • 在項目中添加References:"C:\Program Files\Windows Live\Writer\WindowsLive.Writer.Api.dll"
  • 在項目屬性的"Build Events"=>"Post Build Event command line"添加:(XCOPY /D /Y /R "$(TargetPath)" "C:\Program Files\Windows Live\Writer\Plugins")
 

1、"Class Library"主類,繼承於ContentSource

WintyCodeArea.cs:
using System.Windows.Forms;
using WindowsLive.Writer.Api;
/*
2009-10-02
http://www.blogjava.net/wintys
  */
namespace MyWindowsLiveWriterPlugin
{
    /*Plugin 主類*/
    [WriterPlugin("{7DFB5431-D7DA-4e61-9E4B-056D30DFDB63}",
        "WintyCodeArea",
        PublisherUrl = "http://www.blogjava.net/wintys",
        ImagePath = "image.jpg",
        HasEditableOptions = true,
        Description = "Insert <div class=\"mycode\">your code</div>\nhttp://www.blogjava.net/wintys\[email protected]")]
    [InsertableContentSource("WintyCodeArea")]
    public class WintyCodeArea : ContentSource
    {
        WintyCodeAreaSettings m_settings;
        public override void Initialize(IProperties pluginOptions)
        {
            base.Initialize(pluginOptions);
            m_settings = new WintyCodeAreaSettings(pluginOptions);
        }
        public override DialogResult CreateContent(IWin32Window dialogOwner, ref string content)
        {
            string originalContent = content;
            content = m_settings.FrontCode;
            if(m_settings.EscapeCode)
                content +=  System.Web.HttpUtility.HtmlEncode(originalContent);
            else
                content += originalContent;
            content += m_settings.BackCode;
            return DialogResult.OK;
        }
        public override void EditOptions(IWin32Window dialogOwner)
        {
            SettingForm settingForm = new SettingForm(m_settings);
            settingForm.ShowDialog(dialogOwner);
        }
    }
}
 
         Initialize()、EditOptions()並不是必須的,這裏因爲用到了"設置選項"窗口,才需要。
CreateContent(IWin32Window dialogOwner, ref string content)在此爲必須,content傳入值爲Live Writer當前被選中的高亮區的HTML代碼,無論在編輯還是在源代碼視圖中都是這樣的。content的傳出值爲你修改後的HTML代碼,最終將在Live Writer中顯示的。
        在CreateContent()中也可以彈出窗體,此處並未用到。以下是代碼示例:
public override DialogResult CreateContent(IWin32Window dialogOwner, ref string content)
{
    using (InsertCodeForm insertCodeForm = new InsertCodeForm())
    {
        DialogResult result = insertCodeForm.ShowDialog();
        content = insertCodeForm.MyCode;
        return result;
    }
}
        相應的InsertCodeForm類的部分代碼如下:
public partial class InsertCodeForm : Form
{
    private string m_MyCode;
    public string MyCode
    {
        get { return m_MyCode; }
        set { m_MyCode = value; }
    }
    public InsertCodeForm()
    {
        InitializeComponent();
    }
    private void buttonInsert_Click(object sender, EventArgs e)
    {
        if (textBoxCode.Text == string.Empty)
        {
            return;
        }
        m_MyCode = "<div class=\"mycode\">";
        m_MyCode += System.Web.HttpUtility.HtmlEncode(textBoxCode.Text);
        m_MyCode += "</div>";           
        this.DialogResult = DialogResult.OK;
    }
}

 

2、用於設置WintyCodeArea插件行爲的類

WintyCodeAreaSettings.cs:
using WindowsLive.Writer.Api;
namespace MyWindowsLiveWriterPlugin
{
    class WintyCodeAreaSettings
    {
        IProperties m_properties;
        private const string FRONT_CODE = "FRONT_CODE";//前綴代碼
        private const string BACK_CODE = "BACK_CODE";//後綴代碼
        private const string ESCAPE_CODE = "ESCAPE_CODE";//是否轉義代碼
        public const string DEFAULT_FRONT_CODE = "<div class=\"mycode\">";
        public const string DEFAULT_BACK_CODE = "</div>";
        public const bool   DEFAULT_ESCAPE_CODE = false;
        public WintyCodeAreaSettings(IProperties properties)
        {
            m_properties = properties;
        }
        public string FrontCode
        {
            get
            {
                return m_properties.GetString(FRONT_CODE, DEFAULT_FRONT_CODE);
            }
            set
            {
                m_properties.SetString(FRONT_CODE, value);
            }
        }
        public string BackCode
        {
            get
            {
                return m_properties.GetString(BACK_CODE, DEFAULT_BACK_CODE);
            }
            set
            {
                m_properties.SetString(BACK_CODE, value);
            }
        }
        public bool EscapeCode
        {
            get
            {
                return m_properties.GetBoolean(ESCAPE_CODE, DEFAULT_ESCAPE_CODE);
            }
            set
            {
                m_properties.SetBoolean(ESCAPE_CODE, value);
            }
        }
    }
}

3、"設置窗口"的代碼

        點擊"工具=>選項"就可以找到這個設置窗口。
        WintyCodeArea的設置窗口:
        所謂的轉義原始內容,就是將所選內容中的特殊HTML字符進行編碼(空格與換行不變)。
 
SettingForm.cs:
using System;
using System.Windows.Forms;
namespace MyWindowsLiveWriterPlugin
{
    partial class SettingForm : Form
    {
        WintyCodeAreaSettings m_settings;
        public SettingForm(WintyCodeAreaSettings settings)
        {
            InitializeComponent();
            //Winty's initialization
            m_settings = settings;
            txtFrontCode.Text = m_settings.FrontCode;
            chkEscapeCode.Checked = m_settings.EscapeCode;
            textBackCode.Text = m_settings.BackCode;
        }
        /*保存設置*/
        private void btnOK_Click(object sender, EventArgs e)
        {
            m_settings.FrontCode = txtFrontCode.Text;
            m_settings.EscapeCode = chkEscapeCode.Checked;
            m_settings.BackCode = textBackCode.Text;
            Close();
        }
        /*恢復默認設置*/
        private void btnRestoreDefault_Click(object sender, EventArgs e)
        {
            m_settings.FrontCode = WintyCodeAreaSettings.DEFAULT_FRONT_CODE;
            m_settings.EscapeCode = WintyCodeAreaSettings.DEFAULT_ESCAPE_CODE;
            m_settings.BackCode = WintyCodeAreaSettings.DEFAULT_BACK_CODE;
            txtFrontCode.Text = m_settings.FrontCode;
            chkEscapeCode.Checked = m_settings.EscapeCode;
            textBackCode.Text = m_settings.BackCode;
        }
    }
}
SettingForm.Designer.cs(這是Visual Studio根據設計的窗體生成的代碼):
namespace MyWindowsLiveWriterPlugin
{
    partial class SettingForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.btnOK = new System.Windows.Forms.Button();
            this.chkEscapeCode = new System.Windows.Forms.CheckBox();
            this.labelFont = new System.Windows.Forms.Label();
            this.labelBack = new System.Windows.Forms.Label();
            this.txtFrontCode = new System.Windows.Forms.TextBox();
            this.textBackCode = new System.Windows.Forms.TextBox();
            this.btnRestoreDefault = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // btnOK
            //
            this.btnOK.Location = new System.Drawing.Point(222, 211);
            this.btnOK.Name = "btnOK";
            this.btnOK.Size = new System.Drawing.Size(113, 29);
            this.btnOK.TabIndex = 0;
            this.btnOK.Text = "設置";
            this.btnOK.UseVisualStyleBackColor = true;
            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
            //
            // chkEscapeCode
            //
            this.chkEscapeCode.AutoSize = true;
            this.chkEscapeCode.Location = new System.Drawing.Point(127, 94);
            this.chkEscapeCode.Name = "chkEscapeCode";
            this.chkEscapeCode.Size = new System.Drawing.Size(96, 16);
            this.chkEscapeCode.TabIndex = 1;
            this.chkEscapeCode.Text = "轉義原始內容";
            this.chkEscapeCode.UseVisualStyleBackColor = true;
            //
            // labelFont
            //
            this.labelFont.AutoSize = true;
            this.labelFont.Location = new System.Drawing.Point(48, 12);
            this.labelFont.Name = "labelFont";
            this.labelFont.Size = new System.Drawing.Size(53, 12);
            this.labelFont.TabIndex = 2;
            this.labelFont.Text = "前綴代碼";
            //
            // labelBack
            //
            this.labelBack.AutoSize = true;
            this.labelBack.Location = new System.Drawing.Point(48, 125);
            this.labelBack.Name = "labelBack";
            this.labelBack.Size = new System.Drawing.Size(53, 12);
            this.labelBack.TabIndex = 4;
            this.labelBack.Text = "後綴代碼";
            //
            // txtFrontCode
            //
            this.txtFrontCode.Location = new System.Drawing.Point(125, 12);
            this.txtFrontCode.Multiline = true;
            this.txtFrontCode.Name = "txtFrontCode";
            this.txtFrontCode.Size = new System.Drawing.Size(247, 64);
            this.txtFrontCode.TabIndex = 5;
            //
            // textBackCode
            //
            this.textBackCode.Location = new System.Drawing.Point(125, 125);
            this.textBackCode.Multiline = true;
            this.textBackCode.Name = "textBackCode";
            this.textBackCode.Size = new System.Drawing.Size(247, 64);
            this.textBackCode.TabIndex = 6;
            //
            // btnRestoreDefault
            //
            this.btnRestoreDefault.Location = new System.Drawing.Point(88, 211);
            this.btnRestoreDefault.Name = "btnRestoreDefault";
            this.btnRestoreDefault.Size = new System.Drawing.Size(106, 29);
            this.btnRestoreDefault.TabIndex = 7;
            this.btnRestoreDefault.Text = "恢復默認設置";
            this.btnRestoreDefault.UseVisualStyleBackColor = true;
            this.btnRestoreDefault.Click += new System.EventHandler(this.btnRestoreDefault_Click);
            //
            // SettingForm
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(420, 252);
            this.Controls.Add(this.btnRestoreDefault);
            this.Controls.Add(this.textBackCode);
            this.Controls.Add(this.txtFrontCode);
            this.Controls.Add(this.labelBack);
            this.Controls.Add(this.labelFont);
            this.Controls.Add(this.chkEscapeCode);
            this.Controls.Add(this.btnOK);
            this.Name = "SettingForm";
            this.Text = "WintyCodeArea Settings";
            this.ResumeLayout(false);
            this.PerformLayout();
        }
        #endregion
        private System.Windows.Forms.Button btnOK;
        private System.Windows.Forms.CheckBox chkEscapeCode;
        private System.Windows.Forms.Label labelFont;
        private System.Windows.Forms.Label labelBack;
        private System.Windows.Forms.TextBox txtFrontCode;
        private System.Windows.Forms.TextBox textBackCode;
        private System.Windows.Forms.Button btnRestoreDefault;
    }
}
 

4、總結

        工程最終生成WintyCodeArea.dll,將其複製到"C:\Program Files\Windows Live\Writer\Plugins"目錄,啓動Windows Live Writer就可以使用這個插件了。或將其做成WintyCodeAreaWLWPluginSetup.msi(見附件),點安裝即可(msi製作方法參考[11])。
       此插件主要供自己使用,其他人可能不會想要我的這種效果,所以暫命名WintyCodeArea。但是除了添加<div class="mycode">your code</div>外,還可以進行代碼轉義設置,並且前後綴代碼都可以自定義,根據需要自己添加前綴後綴代碼就行了,所以,希望對別人有點用處。
 
補充:
      如果插件需要訪問剪貼板,可參考如下代碼:
//System.Windows.Forms.Clipboard
IDataObject iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text))
{
    str = (String)iData.GetData(DataFormats.Text);
    ......
}
 
[參考資料]:
[12] MSDN Windows Live Writer SDK : http://msdn.microsoft.com/en-us/library/aa738906.aspx
[13] Windows Live Writer Blog : http://www.live-writer.net/

[附件]:
[1] WintyCodeAreaProject.zip(Visual Studio工程) :
 
[2] WintyCodeAreaWLWPluginSetup.zip(WintyCodeArea插件安裝程序,msi格式) :
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章