[K2 for SharePoint] – Configuration Tip สำหรับ SharePoint 2016

สวัสดีครับ รอบนี้ได้ configure K2 4.7 กับ SharePoint 2016 มาเลยมี tip เพิ่มเติมจาก blog รอบที่แล้ว (ดูได้ที่นี่) มาให้อ่านกัน

ก่อนลง SharePoint 2016 จะเหมือนกับ 2013 คือ ต้องลง prerequisite installer ก่อน แต่ในรอบนี้ ถึงแม้ server เราจะต่อ internet ได้แต่ก็ไม่สามารถ download อะไรได้เลย สุดท้ายก็ต้องมา download เอง แต่เดี๋ยวก่อน!! ถ้าเรา download มาเองแล้วมาลงเอง อาจจะ error ใน step configure SharePoint ได้ ใน step นี้ แนะนำ http://nikcharlebois.com/installing-the-sharepoint-2016-prerequisites-offline-using-powershell/ ให้ download file จากในนี้ได้เลย และให้ใส่ command ตาม เป็นอันจบ

Step หลังจากนี้ ก็ทำเหมือนกับ SharePoint 2013 เลย หลังจากลงเสร็จก็ enable service ตามด้านล่าง (แนะนำให้ใช้ command line ทั้งหมด เพราะว่า ถ้าทำผ่าน UI จะ set บางส่วนไม่ได้)

  • Subscription Service

    $account = Get-SPManagedAccount <Account Name>
    $appPoolSubSvc = New-SPServiceApplicationPool -Name SettingsServiceAppPool -Account $account
    $appSubSvc = New-SPSubscriptionSettingsServiceApplication -ApplicationPool $appPoolSubSvc -Name SettingsServiceApp -DatabaseName <Database Name>
    $proxySubSvc = New-SPSubscriptionSettingsServiceApplicationProxy -ServiceApplication $appSubSvc

  • App Management Service

    $account = Get-SPManagedAccount <Account Name>
    $appPoolAppSvc = New-SPServiceApplicationPool -Name AppServiceAppPool -Account $account
    $appAppSvc = New-SPAppManagementServiceApplication -ApplicationPool $appPoolAppSvc -Name AppServiceApp -DatabaseName <Database Name>
    $proxyAppSvc = New-SPAppManagementServiceApplicationProxy -ServiceApplication $appAppSvc

  • User Profile Service

    $appPool = New-SPServiceApplicationPool -Name HostedAppPool -Account (Get-SPManagedAccount “<Account Name>“)
    $app_UPA = New-SPProfileServiceApplication -Name UPA -PartitionMode -ApplicationPool $appPool

    ตรงนี้จะมีความต่างจาก SharePoint 2013 นิดหน่อย ตรงที่ไม่มี User Profile Synchronization Service ให้ start แต่ในมุมของเราให้สร้าง User Profile Service ให้เรียบร้อย พอสร้างแล้วจะมีปุ่มให้กด Manage

UPS01

Configure Synchronization Connections ให้เรียบร้อย ก็จะใช้งานได้ปกติ

UPS02

UPS03

  • Enable NetBIOS สำหรับ User Profile Service Name ให้ไปดูที่หน้า App Management Service แล้วใส่ชื่อตาม

    $UserProfileServiceApp = Get-SPServiceApplication -name <User Profile Service Name>
    $UserProfileServiceApp.NetBIOSDomainNamesEnabled = 1
    $UserProfileServiceApp.Update()

  • Shell Admin grant SPShellAdmin ให้ user ที่จะเป็นคนรัน app deployment

    Add-SPShellAdmin -UserName <Account Name>
    Get-SPDatabase | ?{$_.Name -eq “<WSS Content DB>“} | Add-SPShellAdmin -Username <Account Name>
    Get-SPDatabase | ?{$_.Name -eq “<SharePoint Admin DB>“} | Add-SPShellAdmin -Username <Account Name>
    Get-SPDatabase | ?{$_.Name -eq “<SharePoint Config DB>“} | Add-SPShellAdmin -Username <Account Name>
    Get-SPDatabase | ?{$_.Name -eq “<App Management Service DB>“} | Add-SPShellAdmin -Username <Account Name>
    Get-SPDatabase | ?{$_.Name -eq “<User Profile Service DB>“} | Add-SPShellAdmin -Username <Account Name>
    Get-SPDatabase | ?{$_.Name -eq “<User Profile DB>“} | Add-SPShellAdmin -Username <Account Name>

ถ้าทำเรียบร้อยก็ให้รัน K2 for SharePoint App Deployment ได้เลย 🙂

Advertisements

Consume REST Services with K2

สวัสดีครับ เนื่องจากใน K2 4.7 มี broker ใหม่เพิ่มเข้ามา และเป็น broker ที่เราน่าจะได้ใช้กันเยอะในอนาคต broker ตัวนี้ก็คือ REST service broker นั่นเอง

การเชื่อมต่อ REST service ใน K2 จะแตกต่างจากการเชื่อมต่อ web service อื่นๆ อยู่ตรงที่ เรารู้แค่ url ของ web service นั้นไม่พอ สิ่งที่ต้องมีถัดไปคือ descriptor file ใน format ของ JSON ถ้าเป็น REST service ที่เราเขียนเองก็อาจจะไม่ยาก เพราะเราสามารถ generate JSON ออกมาจาก swagger ที่เราเขียนได้ แต่ถ้าไม่ได้เขียนเองมี option ตามด้านล่าง

โดยในส่วนที่อยู่ใน blog นี้จะเป็นการเขียนเอง

ถ้าจะเขียน descriptor เอง เราควรรู้อะไรบ้าง?

  • Format ที่ REST Service response ออกมา
  • Swagger syntax ที่จะใช้เขียน เพื่อทำ mapping กับ service ที่เราจะใช้

ผมเลือก service จาก Accuweather (https://developer.accuweather.com) มาลองดู สามารถสมัครมาลองใช้ได้ฟรี แต่ service ก็จะ limit หน่อย (ถ้าใครอยากลอง ก็ไปสมัครแล้ว register app ก็จะได้ API Key ที่ต้องใช้ในมา) ใช้ได้ไม่กี่อัน แต่หลักๆ ของ service ที่มีให้คือ การพยากรณ์ต่างๆ

Weather API

ที่เราจะใช้กันคือ Location API เพื่อหาพื้นที่ที่ต้องการ กับ Forecast API เพื่อดูพยากรณ์ (จริงๆ อยากใช้ Weather Alerts มากกว่า แต่แบบฟรีใช้ไม่ได้ T-T)  อย่างที่บอก เริ่มแรกคือ ต้องไปลองเรียก REST Service เพื่อให้ return response มาซะก่อน

API Response

พอได้ response เราก็เอามาเขียน swagger เพื่อที่จะ generate เป็น descriptor กัน รายละเอียดเกี่ยวกับ swagger ลองอ่านดูตาม link ด้านล่างนะครับ

Tool ที่ผมใช้ในการเขียน swagger ก็มาจาก swagger.io นี่แหละ ใช้เป็นแบบ online เลยง่ายดี สามารถเข้าไปได้ที่ http://editor.swagger.io  ถ้าเขียนเสร็จแล้วก็น่าจะได้ format แบบด้านล่างนี่ล่ะ

Swagger UI

สิ่งที่ควรระวังตอนเขียน swagger คือ ในบางกรณีที่เรามีการเรียกใช้ reference object ซ้อนๆ กัน การประกาศบางแบบอาจจะเรียกใช้ไม่ได้ใน K2 นะครับ แบบที่ใช้ได้จะมีตัวอย่าง file swagger ที่เขียนให้ download ตอนท้ายบทความครับ

เมื่อเขียนเรียบร้อย เราสามารถ generate JSON file ได้โดยเลือกเมนู File -> Download JSON

Download JSON

พอได้ file มา เราก็เอามา register กับ K2 โดยผ่าน SmartObject Service Tester

02-Register REST

03-Register 2

หลังจาก register แล้ว เราก็จะเห็น object ที่สามารถเรียกได้ตามด้านล่าง

04-After Regist

จะเห็นว่า มี method พวก Serialize กับ Deserialize มาด้วย method พวกนี้จะเป็น method สำหรับดึงค่าจาก type ที่ return มาเป็น structure เหมือนกับที่เราใช้ K2 ต่อกับ SAP หรือ web service อื่นๆ จากนั้นลองสร้างเป็น smartobject แล้วทดสอบดู

05-Test City Search

อย่างแรกเลยคือ call City Search เพื่อหาเมือง เพิ่งรู้นะเนี่ยว่า กรุงเทพฯ มีที่อินโดนีเซียด้วย พอได้แล้ว ผมก็เอา Key ไปใช้เพื่อหา forecast ของ 5 วันข้างหน้า

06-5 day forecast

ใน method นี้จะ return Headline หรือคือ พาดหัวข่าวสำคัญ เช่น ฝนจะตกหนักวันไหน กับรายละเอียด forecast มาเป็น object ส่วนที่เราต้องทำถัดไปคือ เอา xml ยาวๆ ที่ได้ ไป call method Deserialize เพื่อให้แสดงผลออกมาเป็น property ออกมา

ส่วนของ Headline ผมได้ xml ตามด้านล่างออกมา

{“$type”:”Accuweather.k2RESTidentifier_Headline, Accuweather, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”,”EffectiveDate”:”2017-08-13T01:00:00+07:00″,”Text”:”A thunderstorm late Saturday night”,”Category”:”thunderstorm”,”Link”:”http://www.accuweather.com/en/th/bangkok/318849/daily-weather-forecast/318849?lang=en-us&#8221;}

ผลหลังจากการ call โอ๊ะ!!! ฝนตกหนักคืนวันเสาร์ตอนดึกๆ

07-Headline Call

ส่วนของพยากรณ์จะได้เป็น array ออกมา

{“$type”:”Accuweather.k2RESTidentifier_DailyForecast[], Accuweather, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”,”$values”:[{“$type”:”Accuweather.k2RESTidentifier_DailyForecast, Accuweather, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”,”Date”:”2017-08-10T07:00:00+07:00″,”Link”:”http://www.accuweather.com/en/th/bangkok/318849/daily-weather-forecast/318849?day=1&lang=en-us&#8221;},{“$type”:”Accuweather.k2RESTidentifier_DailyForecast, Accuweather, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”,”Date”:”2017-08-11T07:00:00+07:00″,”Link”:”http://www.accuweather.com/en/th/bangkok/318849/daily-weather-forecast/318849?day=2&lang=en-us&#8221;},{“$type”:”Accuweather.k2RESTidentifier_DailyForecast, Accuweather, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”,”Date”:”2017-08-12T07:00:00+07:00″,”Link”:”http://www.accuweather.com/en/th/bangkok/318849/daily-weather-forecast/318849?day=3&lang=en-us&#8221;},{“$type”:”Accuweather.k2RESTidentifier_DailyForecast, Accuweather, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”,”Date”:”2017-08-13T07:00:00+07:00″,”Link”:”http://www.accuweather.com/en/th/bangkok/318849/daily-weather-forecast/318849?day=4&lang=en-us&#8221;},{“$type”:”Accuweather.k2RESTidentifier_DailyForecast, Accuweather, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”,”Date”:”2017-08-14T07:00:00+07:00″,”Link”:”http://www.accuweather.com/en/th/bangkok/318849/daily-weather-forecast/318849?day=5&lang=en-us&#8221;}]}

ผลหลังจากการ call ก็เป็นตามด้านล่าง

08-DailyForecast Call

จริงๆ ค่าที่ REST return มามีมากกว่าที่ผมเอามาแสดง แต่ผมเขียน swagger เพื่อเอาค่ามาเฉพาะที่ต้องการเท่านั้น (ขี้เกียจนั่นเอง = =’) ถ้าใครอยากดูตัวอย่างการเขียน swagger กับ file JSON ที่ generate ออกมาได้สามารถ download ได้ตาม link ด้านล่างนะครับ

สำหรับคราวนี้ก็ขอลาแต่เพียงเท่านี้ พบกันใหม่คราวหน้าครับ 🙂

 

 

 

 

[K2 SmartForms] – Using Field Property

สวัสดีครับ หายไปนานกับ blog ของ K2 Ranger พอดีวันนี้มีคำถามเข้ามาทาง page K2 Thailand เกี่ยวกับการเลือก field ที่ผูกกับ data source เลยเอามาเขียนให้อ่านกัน

ในส่วนแรกให้เราสร้าง property field เพิ่มใน file .cs

public string Field

{

get

{

return base.GetOption<string>(“Field”, string.Empty);

}

set

{

base.SetOption<string>(“Field”, value, string.Empty);

}

}

จากนั้นก็ไปเพิ่ม property ใน file definition.xml ของ control

<Prop ID=”Field” mappable=”false” friendlyname=”Field” category=”Detail” refreshdisplay=”false” type=”complex” InitializeServerControl=”initializeFieldPropertyConfig” ClearServerControl=”clearFieldConfig” ServerControl=”SourceCode.Forms.Controls.Web.FieldConfiguration.FieldPropertyConfig,SourceCode.Forms.Controls.Web” />

เพิ่มแล้วเรียบร้อยให้ลอง build แล้ว deploy ใหม่ดู เราก็จะสามารถดึง field ที่อยู่ใน SmartObject ที่ผูกกับ view นี้ออกมาได้

Field

FieldSelection

จะมองเห็นเฉพาะ field type ที่ control นี้สามารถใช้งานได้ด้วย

   ส่วนวิธีเอาค่าจาก Field property ไปใช้ต่อ ก็ใช้วิธีเดียวกันกับการดึงค่าใน property อื่นๆ ไปใช้นะครับ สำหรับรอบนี้ขอลาไปเท่านี้ครับ 🙂

 

[K2 SmartForms] – Can’t click OK to finish rule in designer

สวัสดีครับ หลายๆ คนคงเคยเจอปัญหาอยู่บ้าง เวลาเราใส่ action เข้าไปใน SmartForms เยอะๆ จะไม่สามารถกดปุ่ม OK เพื่อ save action ที่เราใส่เข้าไปได้ หรือกดปุ่ม Finish ที่อยู่ใน form ก็ไม่ได้เช่นกัน ถ้าเคยเจอปัญหานี้ เรามีวิธีแก้ไขมาให้ 2 วิธี โดยทั้ง 2 วิธีเป็นการไปแก้ไข configure ใน web.config ของ SmartForms ที่ site designer (อยู่ใน {install dir}\K2 blackpearl\K2 smartforms Designer)

  • แก้ไขค่า MaxRequestLength จากค่า default เป็น “2097151” ซึ่งเป็นค่ามากที่สุดที่ใส่ได้

designer

  • ถ้าใช้วิธีแรกแล้วยังไม่หาย ให้เพิ่ม tag ตามด้านล่างลงไป ภายใต้ tag requestFiltering

<requestLimits maxAllowedContentLength=”300000000″ />

designer2

เมื่อแก้ไขแล้ว ให้ save web.config และ reset IIS จากนั้นลองใช้งานดู ก็น่าจะ save form ได้ตามปกติครับ  🙂

[K2 SmartForms] – Use SmartObject Property in Custom Control (Part III)

มาต่อจากคราวที่แล้ว ที่เราเลือกเป็น static ไป คราวนี้จะมาลองเลือก SmartObject มาใช้งานกันบ้าง เหมือนกับของ static คือ เราต้องสร้าง property ใน file .cs เพิ่มก่อน โดย property ที่ใช้งานจะมี AssociationSO, AssociationMethod, ValueProperty และ DisplayTemplate

public string AssociationSO

{

get

{

return this.GetOption<string>(“AssociationSO”, string.Empty);

}

set

{

this.SetOption<string>(“AssociationSO”, value, string.Empty);

}

}

public string AssociationMethod

{

get

{

return this.GetOption<string>(“AssociationMethod”, string.Empty);

}

set

{

this.SetOption<string>(“AssociationMethod”, value, string.Empty);

}

}

public string ValueProperty

{

get

{

return this.GetOption<string>(“ValueProperty”, string.Empty);

}

set

{

this.SetOption<string>(“ValueProperty”, value, string.Empty);

}

}

public string DisplayTemplate

{

get

{

return this.GetOption<string>(“DisplayTemplate”, string.Empty);

}

set

{

this.SetOption<string>(“DisplayTemplate”, value, string.Empty);

}

}

สิ่งที่ต้องทำถัดไปคือ สร้าง structure มาเพื่อรับค่าที่เราเก็บไว้ใน DisplayTemplate เพราะตอนที่เราเลือกว่า จะแสดงค่าอะไรออกมาที่ control เราสามารถเลือกได้หลาย field ตามตัวอย่างด้านล่าง

ccb5-01

structure ที่สร้างมาเพื่อรองรับค่า จะใช้ตามด้านล่าง โดยใน DisplayTemplate ที่ K2 เก็บไว้จะเก็บไว้ในรูปของ xml

internal struct DisplayTemplateObject
{

public string SourceType;

public string SourceID;

public string Value;

}

อีกส่วนที่ต้องทำไว้ก่อนคือ การเอา field จาก DisplayTemplate มาต่อกัน เพื่อนำไปใช้ใน control เลยสร้าง method ที่ชื่อ BuildValue ไว้ตามด้านล่าง

private string BuildValue(SmartObject smo, List<DisplayTemplateObject> ParsedTemplate)

{

StringBuilder builder = new StringBuilder();

foreach (DisplayTemplateObject templateObj in ParsedTemplate)

{

if (templateObj.SourceType == “Value”)

{

builder.Append(templateObj.Value);

}

else

{

builder.Append(smo.Properties[templateObj.SourceID].Value);

}

}

return builder.ToString();

}

ทีนี้ก็พร้อมแล้ว เรามาเพิ่ม code ใน CreateChildControls กัน โดยขั้นตอนการทำงานจะทำตาม step ด้านล่าง

  • ตรวจสอบว่า DataSourceType เป็น SmartObject หรือเปล่า?
  • เอาข้อมูล SmartObject, Method และ Value ออกมาจาก property
  • ดึงข้อมูลโดยใช้ class SmartObjectClientServer แบบที่เราเขียนโปรแกรมปกติ
  • ดึงข้อมูล DisplayTemplate มาใส่ใน list โดยแยก attribute มาจาก xml ที่ K2 เก็บไว้ให้
  • นำมาใส่ไว้ใน control ที่ต้องการ

if (this.DataSourceType.Equals(“smartobject”, StringComparison.InvariantCultureIgnoreCase))
{

string smo = this.AssociationSO;
string valueProp = this.ValueProperty;
string smoMethod = this.AssociationMethod;

SmartObjectClientServer smartObjectClient = ConnectionClass.GetSmartObjectClient();
Guid guid = new Guid(smo);
SmartObject smartObject = smartObjectClient.GetSmartObject(guid);
smartObject.MethodToExecute = smoMethod;
SmartObjectList list = new SmartObjectList();

list = smartObjectClient.ExecuteList(smartObject);

List<DisplayTemplateObject> parsedTemplate = new List<DisplayTemplateObject>();

foreach (XElement element in XDocument.Parse(this.DisplayTemplate).Root.Elements())
{

DisplayTemplateObject item = new DisplayTemplateObject

{

SourceType = element.Attribute(“SourceType”).Value

};

if (item.SourceType == “Value”)

{

item.Value = element.Element(“SourceValue”).Value;

}

else

{

item.SourceID = element.Attribute(“SourceID”).Value;

}

parsedTemplate.Add(item);

}

this.ddl = new DropDownList();

List<KeyValuePair<string, string>> showList = new List<KeyValuePair<string, string>>();

foreach(SmartObject item in list.SmartObjectsList)
{

ddl.Items.Add(new ListItem(this.BuildValue(item, parsedTemplate), item.Properties[valueProp].Value));

}

this.Controls.Add(this.ddl);

ในกรณีที่ใส่ code ไปแล้วติด reference บางตัวที่หาไม่เจอ ให้ลอง add dll SourceCode.SmartObjects.Client เพิ่มเข้ามาใน project แล้วก็ add using ตามด้านล่างเข้าไปใน coding ของ control เพิ่ม

using SourceCode.SmartObjects.Client;

using SourceCode.Forms.Controls.Web.SDK.Utilities;

using System.Xml.Linq;

จากนั้นก็ deploy แล้วก็ทดสอบ

ccb5-02

ccb5-03

สำหรับส่วนการ add property ก็จะจบเท่านี้นะครับ เอาไว้พบกันใหม่คราวหน้าครับ 🙂

[Trouble Shooting] – How to solve SmartForms Worklist Control Infinite Spinning

สวัสดีครับ รอบนี้มาคั่นเวลา custom control series นิดหน่อย เนื่องจากเมื่อเช้าได้ช่วยลูกค้าแก้ปัญหา worklist control ของ SmartForms ไม่แสดง worklist ได้แต่หมุนค้างตามรูปด้านล่าง

infiniteworklist01

อย่างแรกที่เราควรไปดูคือ worklist ใน workspace ทำงานได้ไหม? และสามารถใช้งาน service อื่นของ K2 ได้หรือไม่? (service อื่น เช่น start workflow, ใช้งานหน้าจอ SmartForm ที่ไม่มี worklist) ถ้าตรวจสอบแล้วใช้งานได้ ให้ไปดู Web Service URL กับ Web Service URL SSL ใน Environment Library ว่า มีการ set ค่า default ไว้หรือเปล่า?

infiniteworklist02

ถ้าเป็นตามรูปด้านบนที่ไม่ได้ set ไว้ ก็ให้เลือก set อันใดอันหนึ่งให้เป็น default จากนั้น restart service K2 ก็จะสามารถใช้งาน worklist control ของ SmartForms ได้ตามปกติครับ (ถ้ายังไม่ได้ให้ลอง reset IIS กับ clear browser cache ด้วยนะครับ)

ก็ขอจบ tip สั้นๆ ไว้เพียงเท่านี้ ไว้เจอกันใหม่รอบหน้าครับ 😀

[K2 SmartForms] – Use SmartObject Property in Custom Control (Part II)

สวัสดีครับ เรามาต่อจากคราวที่แล้วที่เราสามารถเรียกหน้า configure SmartObject ขึ้นมาแสดงได้แล้ว (ถ้ายังไม่ได้เคยอ่าน ดูได้จาก https://k2ranger.wordpress.com/2017/02/20/k2-smartforms-use-smartobject-property-in-custom-control-part-i/  พอแสดงได้แล้ว ในหน้า configure จะมีให้เลือกอยู่ 2 แบบด้วยกัน คือ เลือกเป็น static หรือ SmartObject ในวันนี้เราจะมาพูดในส่วนของ static ก่อน

ในตอนที่แล้ว เราเพิ่ม property ไว้ใน xml หลาย property แต่ยังไม่ได้สร้าง property จริงๆ ใน coding ให้เราไปสร้าง property ใน file .cs ของเราเพิ่ม โดยในการใช้งานส่วนของ static จะใช้แค่ 2 properties ตามด้านล่าง คือ DataSourceType กับ FixedListItems

public string DataSourceType

{

get

{

                return this.GetOption<string>(“dataSourceType”, string.Empty);

}

set

{

                this.SetOption<string>(“dataSourceType”, value, string.Empty);

}

}

public string FixedListItems

{

get

{

                return this.GetOption<string>(“FixedListItems”, string.Empty);

}

set

{

                this.SetOption<string>(“FixedListItems”, value, string.Empty);

}

}

เมื่อเพิ่มแล้วให้เรามาดูเพิ่ม checking ใน method CreateChildControls ในตัวอย่างด้านล่างนี้ ผมจะเช็คว่า ค่าใน DataSourceType เป็น static หรือเปล่า? ถ้าเป็น static ก็จะตรวจสอบ FixedListItems ต่อว่า มีค่าไหม?

ccb4-01

ถ้ามีค่า ก็จะทำการ Deserialize xml (เนื่องจากเวลาเราสร้าง list item เก็บไว้ จะเก็บไว้ใน format ของ xml) ออกมาเป็น list จากนั้นก็วน loop เพื่อ add เข้า dropdownlist เพื่อแสดงค่า และในส่วนสุดท้ายต้องไม่ลืม add dropdownlist เข้าไปใน control ที่จะ render ด้วย (ใน class ผมมีไปประกาศ ddl เป็น dropdownlist แบบ private ไว้ เพื่อเอามาใช้แสดงผลด้วย)

this.ddl = new DropDownList();

if (this.DataSourceType.Equals(“static”, StringComparison.InvariantCultureIgnoreCase))

{

if (!string.IsNullOrEmpty(this.FixedListItems))

{

using (StringReader reader = new StringReader(this.FixedListItems))

{

bool flag = true;

List<StaticItem> list = null;

                        if (this.FixedListItems.StartsWith(“[“))

{

JavaScriptSerializer serializer = new JavaScriptSerializer();

try

{

list = serializer.Deserialize<List<StaticItem>>(this.FixedListItems);

}

catch (ArgumentException)

{

flag = false;

}

if (flag)

{

foreach (StaticItem item in list)

{

ddl.Items.Add(new ListItem(HttpUtility.HtmlEncode(item.Display), HttpUtility.HtmlEncode(item.Value)));

}

this.Controls.Add(ddl);

}

}

else

                        {

flag = false;

                        }

}

}

}

ในกรณีที่ใส่ code ไปแล้วติด reference บางตัวที่หาไม่เจอ ให้ลอง add dll SourceCode.Forms.Utilities เพิ่มเข้ามาใน project แล้วก็ add using ตามด้านล่างเข้าไปใน coding ของ control เพิ่ม

using SourceCode.Forms.Controls.Web.SDK;

using SourceCode.Forms.Controls.Web.SDK.Attributes;

using System.IO;

using System.Web.Script.Serialization;

using SourceCode.Forms.Utilities;

using System.Xml;

เมื่อทำการ deploy เรียบร้อยก็มาทดสอบกัน โดยใส่ข้อมูลเป็น static list

ccb4-02

ccb4-03

จะเห็นว่า ข้อมูลถูกแสดงออกมาอย่างที่อยากได้ใน dropdownlist แต่ถ้าอยากเอาข้อมูลออกมาใช้งานต่อ ก็ต้องไป implement javascript เพื่อ get ค่าจาก control ออกมาอีกรอบนะครับ สำหรับคราวนี้ก็ขอจบการดึง data จาก static list มาแสดงใน control แต่เพียงเท่านี้ แล้วค่อยมาต่อกันรอบหน้าสำหรับการดึงข้อมูลจาก SmartObject มาแสดงครับ 🙂

 

[K2 SmartForms] – Use SmartObject Property in Custom Control (Part I)

สวัสดีครับ กลับมาคราวนี้เราจะมาคุยกันต่อเรื่อง property ของ custom control กัน จาก blog คราวที่แล้วเราได้ลองสร้าง property ที่เป็นแบบทั่วไป (type เป็น string, number, boolean etc.) กันไปแล้ว แต่จะมีอีกคำถามว่า ถ้าเราอยากทำ control ที่ดึงข้อมูลจาก SmartObject ล่ะจะทำได้ยังไงบ้าง?

ccb3-01

นี่แหละหน้าตาแบบที่เราอยากได้

    วิธีการเพิ่มเข้าไปก็จะเหมือนกับแบบทั่วไป คือเพิ่มเข้าไปใน xml schema ของ control ที่เราสร้าง

  • ส่วนแรกเป็นการเพิ่ม DataSourceType ที่น่าสนใจคือ เราต้องระบุ type เป็น “complex” และต้องระบุ serverControlType, InitializeServerControl, ClearServerControl และ ServerControl attribute เข้าไป ซึ่งส่วนนี้จะเป็นการเรียกใช้ control ที่ SmartForms มีมาอยู่แล้ว มาแสดงอยู่ใน property ของ control

<Prop ID=”DataSourceType” mappable=”false” friendlyname=”Type” type=”complex” serverControlType=”property” category=”Data Source” refreshdisplay=”true” InitializeServerControl=”initCommonDataSourceConfig” ClearServerControl=”clearComplexPropertyConfig” ServerControl=”SourceCode.Forms.Controls.Web.PropertyConfiguration.AssociationPropertyConfig,SourceCode.Forms.Controls.Web” />

  • ใน option ของการเลือก SmartObject จะมีให้กำหนดเป็น static list ได้ property FixedListItems จะเป็นตัวที่ไว้ใช้เก็บ static list ที่เรากำหนด

<Prop ID=”FixedListItems” mappable=”false” friendlyname=”Items” type=”string” serverControlType=”property” category=”Data Source” ReadOnly=”true” />

  • AssociationSO ไว้เก็บ SmartObject ที่เราเลือกใช้

<Prop ID=”AssociationSO” mappable=”false” friendlyname=”SmartObject” type=”string” serverControlType=”smartobject” category=”Data Source” ReadOnly=”true” />

  • AssociationMethod ไว้เก็บ method ที่เราเลือกใช้

<Prop ID=”AssociationMethod” mappable=”false” friendlyname=”Method” type=”string” serverControlType=”listmethod” category=”Data Source” ReadOnly=”true” />

  • ValueProperty ไว้เก็บ property ที่เราเลือกมาเป็น value ของ control

<Prop ID=”ValueProperty” mappable=”false” friendlyname=”Value” type=”string” serverControlType=”property” category=”Data Source” ReadOnly=”true” />

  • DisplayTemplate ไว้เก็บ property ที่เราเลือกมาเป็น display ของ control

<Prop ID=”DisplayTemplate” mappable=”false” friendlyname=”Display” type=”string” serverControlType=”property” category=”Data Source” ReadOnly=”true” />

ที่ใส่ไปด้านบนจะเป็นเฉพาะส่วนที่เราต้องการใช้งาน แต่จริงๆ แล้วยังมี property ส่วนอื่นที่ใช้ได้เพิ่มเติม อย่างเช่น lookup ข้อมูลจาก SmartObject ที่ทำ Association ไว้ หรือ filter ข้อมูลจากการ list control อื่น ซึ่งยังไม่พูดถึงตอนนี้ ถ้าเราใส่เพิ่มเข้าไปใน file .xml ของ control แล้ว ให้ลอง build แล้ว deploy ดู เมื่อลอง add control เข้ามาแล้วไปดูที่ property จะเห็นรูปตามด้านล่าง

ccb3-02

เมื่อกดปุ่ม … ก็จะได้ popup ส่วนที่เป็นการเลือก SmartObject ขึ้นมา จะเห็นว่า มีให้เลือกเป็น static list และเลือกจาก SmartObject

ccb3-03

เมื่อเราเลือก SmartObject ที่ต้องการแล้วกดปุ่ม OK  ข้อมูลที่เลือกไว้ก็จะแสดงอยู่ในหน้า property

ccb3-04

มาถึงตรงนี้ เราก็จะได้ control ที่สามารถเก็บ SmartObject ที่ต้องการใช้ได้แล้ว ส่วนการเอาค่าที่เก็บไว้ไปใช้งานเราจะมาต่อกันรอบหน้าครับ 🙂

[K2 SmartForms] – Add property for your custom control

สวัสดีครับ กลับมาต่อกันใน blog ที่สองของ series การเขียน custom control ด้วยตนเอง (!? หืมม เคยตั้งชื่อด้วยเหรอออ = =’) ในคราวนี้ เราจะมาลองเพิ่ม property ง่ายๆ ให้ control ของเรากัน ถ้าใครยังไม่รู้วิธีสร้าง custom control project ให้ไปดูที่ blog แรกก่อนนะครับ (https://k2ranger.wordpress.com/2017/01/26/k2-smartforms-custom-control-for-beginner/)

ตอนที่สร้าง control มาจาก template เราจะได้ control default มาเป็น textbox ดังนั้นใน blog นี้ ผมจะเพิ่ม property ให้ textbox นี้กลายเป็น password textbox ได้ โดยสิ่งที่ต้องทำอย่างแรกคือ เปิด file xml ของ control ขึ้นมา

ccb2-01

จากนั้นให้หา section “Properties” แล้ว add property เพิ่มเข้าไป โดยมีรายละเอียดตามด้านล่าง

  • ID => ชื่อของ property
  • friendlyname =>label ที่จะปรากฏอยู่ในช่อง property ของ control
  • type => datatype ของ property ในกรณีนี้อยากได้แค่ checkbox ก็ใส่เป็น boolean ไป
  • category => แสดง control ใน category ไหน
<Prop ID="DisplayPasswordStyle" friendlyname="Display password style" type="bool" category="General" />

ccb2-02

ขั้นถัดไปให้ไปเปิด file .cs แล้วใส่ get set method สำหรับกำหนดค่า property ที่เราเพิ่มเข้ามา ในส่วนนี้ class ของ K2 ที่เรา inherit มา จะมี method สำหรับ get กับ set ค่าให้อยู่แล้ว ชื่อ GetOption กับ SetOption

public bool DisplayPasswordStyle
{
            get
            {
                return this.GetOption<bool>("displaypasswordstyle", true);
            }
            set
            {
                this.SetOption<bool>("displaypasswordstyle", value, true);
            }
}

 

ccb2-03

ส่วนสุดท้ายที่เราต้องทำคือ ควบคุมการ render control ในส่วนนี้จะมีอยู่ 2 methods ที่ใช้ได้คือ CreateChildControls กับ RenderContents (ถ้าใครเคยเขียน web part ของ SharePoint มาก่อน ก็น่าจะคุ้นเคยกับ method พวกนี้อยู่ เพราะจะทำงานแบบเดียวกัน) แต่แนะนำให้ใช้ CreateChildControls จะง่ายกว่า

ในส่วนนี้ผมจะตรวจสอบว่า มีการเลือกให้ Display เป็น password ไหม ถ้าเลือกให้ display เป็น password ก็จะใส่ attribute เพิ่มเข้าไป

if (DisplayPasswordStyle)
{
    base.Attributes["type"] = "password";
}

ccb2-04

เมื่อทำตามครบแล้ว ให้ build solution จากนั้นก็ deploy เข้า server K2 โดยการ deploy ก็ทำไม่ยาก เพราะใน template จะทำ file .bat สำหรับคำสั่ง copy dll และ register control เข้า server ให้แล้ว (ใน .bat จะ copy ไปที่ drive c: นะครับ ถ้าใครลง K2 ไว้ drive อื่น หรือไม่ใช่ folder default จะต้องแก้ file .bat อีกที) file .bat จะอยู่ใน bin folder ของ project ที่เราสร้าง จะมีชื่อว่า “RegisterCustomControl”

ccb2-05

ให้รัน .bat รอจนขึ้น Complete ตามด้านล่าง แสดงว่า การ deploy เสร็จเรียบร้อย

ccb2-06

สุดท้ายคือ การทดสอบ เมื่อเราเปิดหน้า designer จะเจอ control ที่เรา register มา เมื่อลากมาวาง ก็จะเห็น property ที่เราเพิ่มเข้ามา

ccb2-07

ถ้าเราเลือกให้แสดงผลเป็น password control ก็จะแสดงค่าที่พิมพ์เป็น * แทนที่จะเป็นตัวอักษรปกติ

ccb02-08

สำหรับคราวนี้ก็ขอจบเท่านี้นะครับ ถ้าใครเอาไปลองสร้าง control อะไรก็เอามาแชร์กันบ้างนะครับ ไว้เจอกันใหม่คราวหน้ากับรายละเอียดส่วนอื่นของการสร้าง custom control 🙂

[K2 SmartForms] – Custom Control for Beginner

สวัสดีครับ กลับมาคราวนี้เรามาเจอกันกับการเขียน SmartForms Custom Control ที่หลายๆ คนอยากรู้กัน ใน blog แรกของ series SmartForms Custom Control นี้ จะเน้นที่การอธิบายวิธีการเตรียมตัว กับส่วนประกอบของ custom control กันก่อน

ก่อนที่จะเริ่มเขียนกัน ให้ไป download Visual Studio Template จาก http://community.k2.com/t5/K2-blackpearl/Visual-Studio-Project-Templates-for-K2-blackpearl-Extensions/ba-p/1081 ซะก่อน (เลือก template version ตาม Visual Studio ที่เราจะใช้ด้วยนะครับ) การมี template จะช่วยให้เราสร้าง custom control ได้ง่ายขึ้น

หลังจาก download และลงเรียบร้อยแล้ว เราก็มาเริ่มขั้นแรกคือ สร้าง Custom Control Project ขึ้นมา โดยให้เลือกเป็น “Custom SmartForm Control Project”

01

หลังจากสร้างแล้ว เราจะได้ project หน้าตาตามด้านล่าง

ccb01

จะเห็นว่า project template add batch file สำหรับ register control มาให้ด้วย รวมถึง signing key ที่จำเป็นในการสร้าง custom control สิ่งที่เราจะทำถัดไปคือ add new item เข้ามาใหม่ ในส่วนของ SmartForms จะมี 2 แบบคือ Server Control กับ Client Control ในกรณีของเราให้เลือกเป็น Client Control

ccb03

หลังจาก Add Client Control มาแล้ว เราจะได้ folder เพิ่มเข้ามา พร้อมทั้ง file ที่ต้องใช้ในการทำ custom control คือ

  1. File .cs => สำหรับใส่คำสั่งที่เป็น server side
  2. File .xml => สำหรับ register control เข้ากับ K2 โดยจะมีรายละเอียดต่างๆ ของ control
  3. File .js => สำหรับใส่คำสั่งที่เป็น client side (มีได้มากกว่า 1 file)
  4. File .css => สำหรับใส่ stylesheet เฉพาะของ control (มีได้มากกว่า 1 file)

ccb02

โดย file .xml, .js และ .css ต้องเลือก property ของ Build Action ของ file เป็น “Embedded Resource” ด้วย (file ที่ template สร้างให้จะเป็น Embedded Resource) อยู่แล้ว

ccb04

สำหรับ blog แรกเกี่ยวกับ Custom Control ขอจบที่การอธิบายส่วนประกอบเท่านี้ก่อน ส่วนครั้งหน้าเราจะทำเริ่มทำ custom control จริงๆ กันครับ 🙂