|
มารู้จักกับคำว่า Bound Data และ UnBound Data Control
- Bound Data Control คือ การผูก (Bound) ตารางข้อมูล (RecordSet) เข้ากับพวก Component หรือ Control ต่างๆ ผ่านทาง DataSource กรณีที่นำมาใช้แสดงผลลงในตารางกริด มันจะอ่านค่าฟิลด์ต่างๆ เพื่อแสดงผลในแต่ละหลัก เรียงตามลำดับจากการ Query ที่เราเขียนไว้ และ ต้องแสดงทุกๆฟิลด์ออกมาทั้งหมด (หากไม่ต้องการแสดงผล จะต้องทำการซ่อนหลักของตัวกริดเอง) มีข้อดี คือ ทำงานได้เร็ว มักนำไปแสดงผลข้อมูลอย่างเดียว (อ่านรายละเอียดและดาวน์โหลดโค้ดได้ที่นี่)
- UnBound Data Control ก็จะไม่มีการผูก (Unbound) ตารางข้อมูลใดๆเข้ากับ Component หรือ Control การนำไปใช้ในตารางกริด ไม่จำเป็นต้องแสดงผลออกมาทุกฟิลด์ และ จะเอาตัวไหนมาแสดงในหลักใดๆก่อนหลังก็ได้ มีข้อดี คือ ยืดหยุ่นมากกว่า และ มักใช้กับการแก้ไขข้อมูลของตารางกริดในแต่ละ Cell ได้นั่นเอง กรณีของ UnBound Data จะไม่ผูกแหล่งจ่าย หรือ DataSource เข้ากับตัว SharpGrid แต่จะอาศัยการวนลูป หรือการทำซ้ำแทน
Download SharpGrid ActiveX/COM Grid Control (เฉพาะสมาชิกเท่านั้น) ...
เพิ่มเติมจากวิธีการ BoundData วิธีการในการเข้าถึงข้อมูลในแต่ละเซลล์ เราสามารถใช้ Method CellAt(แถว, หลัก) เพื่อการเข้าถึงข้อมูลได้อย่างรวดเร็ว ...
- ' / -----------------------------------------------------------------------------------------------
- ' / อ่านค่า Primary Key จากหลัก 0 ที่ถูกซ่อนเอาไว้ เพื่อนำไปใช้งานอย่างอื่นต่อไป
- Private Sub SGGridEmployee_DblClick()
- ' / -----------------------------------------------------------------------------------------------
- '// การเข้าถึงข้อมูลในแต่ละเซลล์ SharpGrid.CellAt(แถวที่เลือก, หลักที่ต้องการ)
- MsgBox "EmployeePK = " & SGGridEmployee.CellAt(SGGridEmployee.Row, 1) & vbCrLf & _
- "EmployeeName = " & SGGridEmployee.CellAt(SGGridEmployee.Row, 3)
- End Sub
คัดลอกไปที่คลิปบอร์ด
มาดูโค้ดส่วนของฟอร์มหลัก ...
- ' / -----------------------------------------------------------------------------------------------
- ' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
- ' / eMail : thongkorn@hotmail.com
- ' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
- ' / Facebook: https://www.facebook.com/g2gnet (For Thailand only)
- ' / Facebook: https://www.facebook.com/commonindy (World Wide)
- ' /
- ' / Purpose : Sample to use SharpGrid ActiveX for UnBound Data Control.
- ' / Microsoft Visual Basic 6.0 Service Pack 6 + MS Access 2003
- ' / -----------------------------------------------------------------------------------------------
- Option Explicit
- ' / -----------------------------------------------------------------------------------------------
- Private Sub Form_Load()
- ' / -----------------------------------------------------------------------------------------------
- '/ Trap Error
- On Error GoTo ErrorHandler
- '// การตั้งฟอร์มไว้กึ่งกลางจอภาพในแบบ Run Time
- Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
- '// ทำการติดต่อกับฐานข้อมูลก่อน (modDataBase.bas)
- Call OpenDataBase
- '// เคลียร์ค่า TextBox
- txtSearch.Text = ""
-
- '// ตั้งค่าการแสดงผล SharpGrid
- Call InitSGGrid
- '// ส่งค่า False เพื่อแจ้งโปรแกรมย่อยว่าแสดงผลข้อมูลออกมาทั้งหมด
- Call SGGridEmployeeBound(False)
-
- ExitProc:
- Exit Sub
-
- ErrorHandler:
- MsgBox "Error : " & Err.Number & vbCrLf & Err.Description, vbOKOnly + vbExclamation, "รายงานความผิดพลาด"
- Resume ExitProc
- '
- End Sub
- ' / -----------------------------------------------------------------------------------------------
- Sub InitSGGrid()
- ' / -----------------------------------------------------------------------------------------------
- ' Initialize grid properties
- With SGGridEmployee
- '/ ++++++++++++++++++++++++++++++++++++++++
- '/ กำหนดการแสดงผล GroupHeader หรือไม่
- '/ False คือ ไม่ต้องแสดงผล
- .GroupByBoxVisible = False
- '/ True จะแสดงผล GroupHeader ซึ่งจะทำให้ผู้ใช้งานลาก Column ไปจัดกลุ่มได้
- '/ ++++++++++++++++++++++++++++++++++++++++
-
- .FitLastColumn = True
- .Appearance = sg3D
- .SpecialMode = sgModeListBox
- .CellsBorderVisible = True
- .AutoResize = sgAutoResizeColumns
- .GroupIndentation = 225
-
- .DefaultRowHeight = 390
- .RowHeightMin = 390
- .HeadingColCount = 1
-
- .HeadingGridLinesColor = vbBlack
- .HeadingGridLines = sgGridLineFlat
-
- '/ สลับสีแถว
- .EvenOddStyle = sgEvenOddRows
- .ColorOdd = &HEFEFE0
-
- .CellTips = sgCellTipsFloat
- .CellTipsDelay = 400
- .ScrollBarTips = sgScrollTipsVertical
-
- .CacheAllRecords = True
- .ColumnClickSort = True
-
- '/ การแสดงผลปกติทั่วไป
- With .Styles("Normal")
- .BkgStyle = sgCellBkgSolid
- .Font.Name = "Tahoma"
- .Font.Size = 8
- .Padding = 18
- End With
-
- '/ ส่วนหัวของ Header กรณีการแสดงผลทั่วไป
- With .Styles("Heading")
- .BackColor = RGB(0, 153, 255)
- .ForeColor = vbWhite
- .Font.Name = "Tahoma"
- .Font.Size = 9
- .Font.Bold = True
- .Padding = 75
- End With
-
- '/ ส่วนหัวของ GroupHeader กรณีมีการจัดกลุ่ม
- With .Styles("GroupHeader")
- .Font.Size = 9
- .Font.Bold = True
- .BackColor = RGB(241, 239, 226)
- .BkgStyle = sgCellBkgSolid
- .Padding = 30
- .BorderColor = RGB(241, 207, 0)
- .Borders = sgCellBorderBottom
- .BorderSize = 1
- End With
-
- '/ ส่วนของ GroupFooter กรณีมีการจัดกลุ่ม
- With .Styles("GroupFooter")
- .Font.Size = 9
- .Font.Name = "Tahoma"
- .ForeColor = vbBlue
- .BackColor = RGB(255, 255, 224)
- .BkgStyle = sgCellBkgSolid
- .Padding = 75
- .BorderColor = RGB(255, 207, 0)
- .Borders = sgCellBorderBottom
- .BorderSize = 50
- .TextAlignment = sgAlignLeftCenter
- End With
-
- With .Styles("Tip")
- .Font.Size = 10
- .Padding = 40
- End With
-
- '/ กำหนดสีให้แถบแสงที่เราเลือกแถว
- With .Styles("Selection")
- .BackColor = RGB(0, 170, 0)
- .ForeColor = vbWhite
- .BkgStyle = sgCellBkgSolid
- End With
-
- '/ กำหนดสีให้แถบแสง กรณีที่เราไม่ได้เลือกแถวนั้น
- With .Styles("InactiveSelection")
- .BackColor = RGB(0, 170, 0)
- .ForeColor = vbWhite
- .BkgStyle = sgCellBkgSolid
- End With
- End With
- End Sub
- ' / -----------------------------------------------------------------------------------------------
- ' / อ่านค่า Primary Key จากหลัก 0 ที่ถูกซ่อนเอาไว้ เพื่อนำไปใช้งานอย่างอื่นต่อไป
- Private Sub SGGridEmployee_DblClick()
- ' / -----------------------------------------------------------------------------------------------
- '// การเข้าถึงข้อมูลในแต่ละเซลล์ SharpGrid.CellAt(แถวที่เลือก, หลักที่ต้องการ)
- MsgBox "EmployeePK = " & SGGridEmployee.CellAt(SGGridEmployee.Row, 1) & vbCrLf & _
- "EmployeeName = " & SGGridEmployee.CellAt(SGGridEmployee.Row, 3)
- End Sub
- ' / -----------------------------------------------------------------------------------------------
- ' / ตัวแปร blnSearch เป็นออพชั่น หากไม่มีการส่งค่ามา ให้ถือว่ามันมีค่าเป็น FALSE
- ' / หาก blnSearch = False เป็นการแสดงผลข้อมูลทั้งหมด โดยไม่ต้องทำการค้นหา
- ' / หาก blnSearch = True เป็นการค้นหาข้อมูล ตามเงื่อนไขที่อยู่ใน TextBox
- Sub SGGridEmployeeBound(Optional blnSearch As Boolean = False)
- ' / -----------------------------------------------------------------------------------------------
- With SGGridEmployee
- '.Columns.RemoveAll False
- '/ +++++++++++++++++++++++++++++++++++++++++++++++
- '/ ต้องกำหนดจำนวนหลักให้กับ SharpGrid กรณีที่ใช้งานแบบ UnBound
- '/ หากไม่ต้องการกำหนดจำนวน เราสามารถใช้ Method Add Column แทน
- .DataColCount = 7
- '/ +++++++++++++++++++++++++++++++++++++++++++++++
- .DataRowCount = 0
- ' / หลัก 0 นี่คือหลักที่แสดงหมายเลขแถวครับ
- .Rows.At(0).Height = 420
- .ColumnClickSort = True
- .Columns(0).Width = 400
- .Columns(0).AllowSizing = False
- .Columns(0).Hidden = True
- .RowNumbering = False
- End With
-
- '/ สร้าง Instance ขึ้นมาใหม่ พร้อมตัดการเชื่อมต่อเดิมทิ้ง (หากลืม)
- Set RS = New ADODB.Recordset
- '/ blnSearch = True คือการค้นหาข้อมูล
- If blnSearch Then
- '// Bound Data จะแสดงผลโดยจัดเรียงข้อมูลตามฟิลด์ ที่อยู่ใน Query
- '// หากฟิลด์ใดที่เราไม่ต้องการให้แสดงผล ต้องไปตั้งค่าหลักนั้นใน SharpGrid ให้ Hidden = True
- Statement = _
- " SELECT tblEmployee.EmployeePK, tblEmployee.EmployeeID, tblEmployee.EmployeeName, tblPosition.PositionName, " & _
- " tblDepartment.DepartmentName, tblEmployee.DateStart, tblEmployee.Salary " & _
- " FROM (tblEmployee INNER JOIN tblDepartment ON tblEmployee.DepartmentFK = tblDepartment.DepartmentPK) INNER JOIN " & _
- " tblPosition ON tblEmployee.PositionFK = tblPosition.PositionPK " & _
- " WHERE " & _
- " ([EmployeeID] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
- " [EmployeeName] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
- " [PositionName] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
- " [DepartmentName] " & " Like '%" & Trim(txtSearch.Text) & "%'" & ")" & _
- " ORDER BY EmployeeID, EmployeeName "
-
- '// blnSearch = False คือ แสดงผลทั้งหมด
- Else
- Statement = _
- " SELECT tblEmployee.EmployeePK, tblEmployee.EmployeeID, tblEmployee.EmployeeName, tblPosition.PositionName, " & _
- " tblDepartment.DepartmentName, tblEmployee.DateStart, tblEmployee.Salary " & _
- " FROM (tblEmployee INNER JOIN tblDepartment ON tblEmployee.DepartmentFK = tblDepartment.DepartmentPK) INNER JOIN " & _
- " tblPosition ON tblEmployee.PositionFK = tblPosition.PositionPK " & _
- " ORDER BY DepartmentName, EmployeeID "
- End If
-
- ' ============ IMPORTANT ==========
- ' / ระบุให้ทำงานในโหมด UNBOUND DATA
- SGGridEmployee.DataMode = sgUnbound
- ' ==================================
- RS.CursorLocation = adUseClient
- '// adOpenForwardOnly และ adLockReadOnly เป็นการอ่านข้อมูลเดินหน้าอย่างเดียว จะมีความเร็วในการนำข้อมูลมาแสดงผล
- RS.Open Statement, ConnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
-
- '/ =============== ผูกเข้ากับตาราง RecordSet ================
- '/ BOUND DATA
- '/ เหมือนการกำหนด DataSource ใน VB.NET
- 'Set SGGridEmployee.DataSource = RS
- '/ ====================================================
- '/ แสดงจำนวนรายการ
- SGGridEmployee.DataRowCount = RS.RecordCount
- If RS.RecordCount >= 0 Then
- lblSearch.Caption = "[จำนวน : " & RS.RecordCount & " รายการ.]"
- Else
- lblSearch.Caption = "[จำนวน : 0" & " รายการ.]"
- End If
-
- '// จัดรูปแบบหลักใหม่
- Call SetupSGGrid
-
- '// ++++++++++++++++++ UNBOUND DATA +++++++++++++++++++
- '// การ UnBound ก็คือการทำ Loop หรือการทำซ้ำ (Repetitive) นั่นเอง
- '// โดยที่เราเลือกมาเฉพาะบางฟิลด์ก็ได้ ไม่จำเป็นต้องนำมาจากการ Query ทั้งหมด
- Dim Rec As Long
- '// ที่เลือก FOR ก็เพราะว่ามันมีค่าเริ่มต้น - สิ้นสุด และมีการนับเพิ่ม (หรือลด) แบบคงที่
- '// ลองแก้ไขโดยใช้ Do While หรือ Do Until แทนครับผม
- For Rec = 1 To SGGridEmployee.DataRowCount
- With SGGridEmployee
- .CellAt(Rec, 1) = RS("EmployeePK")
- ' / การใส่ "" ไว้ด้านหน้าฟิลด์ข้อมูลแบบ String เพื่อป้องกัน Error หากมีค่าเป็น Null
- .CellAt(Rec, 2).Value = "" & RS("EmployeeID")
- .CellAt(Rec, 3).Value = "" & RS("EmployeeName")
- .CellAt(Rec, 4) = "" & RS("PositionName")
- .CellAt(Rec, 5) = "" & RS("DepartmentName")
- .CellAt(Rec, 6) = "" & Format(RS("DateStart"), "dd/MM/yyyy")
- .CellAt(Rec, 7) = Format(RS("Salary"), "#,##0.00")
- End With
- RS.MoveNext
- Next
- ' / Always must be disconnect RecordSet
- RS.Close: Set RS = Nothing
- End Sub
- ' / -----------------------------------------------------------------------------------------------
- ' / การตั้งค่าหลักต่างๆ ต้องให้ตรงกันกับฟิลด์ข้อมูลในการ Query จากโปรแกรมย่อย SGGridEmployeeBound
- Private Sub SetupSGGrid()
- ' / -----------------------------------------------------------------------------------------------
- '/ การกำหนดโหมด Bound Data ทำให้เกิดการนับจำนวนหลักเอาไว้ให้เรียบร้อย
- ' ================ Setup SGGrid ====================
- With SGGridEmployee
- '// Start Columns 1 โดยใช้ค่า Index ที่เรียงมาจาก Query
- With .Columns(1)
- '/ แสดงผลหัวข้อหลัก
- .Caption = "EmployeePK"
- '/ ความกว้างเป็น 0
- .Width = 0
- '/ ไม่ยอมให้ปรับขนาดความกว้างของหลัก
- .AllowSizing = False
- '/ เอาไปซ่อนจากสายตาผู้ใช้ไปเลย กรณีที่เราไม่ต้องการให้หลักนี้มีการแสดงผลให้ผู้ใช้งานเห็น
- .Hidden = True
- End With
- ' 2
- With .Columns(2)
- .Caption = "รหัสพนักงาน"
- '/ ตั้งค่าการแสดงตำแหน่งของข้อมูล
- .Style.TextAlignment = sgAlignLeftCenter
- .HeadingStyle.TextAlignment = sgAlignLeftCenter
- .AllowSizing = True
- End With
- ' 3
- With .Columns(3)
- .Caption = "ชื่อ - นามสกุล"
- .Style.TextAlignment = sgAlignLeftCenter
- .HeadingStyle.TextAlignment = sgAlignLeftCenter
- .AllowSizing = True
- End With
- ' 4
- With .Columns(4)
- .Caption = "ตำแหน่ง"
- .Style.TextAlignment = sgAlignLeftCenter
- .HeadingStyle.TextAlignment = sgAlignLeftCenter
- .AllowSizing = True
- End With
- ' 5
- With .Columns(5)
- .Caption = "แผนก"
- .Style.TextAlignment = sgAlignLeftCenter
- .HeadingStyle.TextAlignment = sgAlignLeftCenter
- .AllowSizing = True
- End With
- ' 6
- With .Columns(6)
- .Caption = "วันที่เริ่มทำงาน"
- .Style.TextAlignment = sgAlignRightCenter
- .HeadingStyle.TextAlignment = sgAlignRightCenter
- .Style.Format = "dd/mm/yyyy"
- .AllowSizing = True
- End With
- ' 7
- With .Columns(7)
- .Caption = "เงินเดือน"
- .Style.TextAlignment = sgAlignRightCenter
- .HeadingStyle.TextAlignment = sgAlignRightCenter
- .DataType = sgtCurrency
- .Style.Format = "#,##0.00"
- .AllowSizing = False
- End With
- '
- End With
- End Sub
- ' / -----------------------------------------------------------------------------------------------
- ' / กดปุ่ม Refresh เพื่อทำการแสดงผลข้อมูลทั้งหมด
- Private Sub cmdRefresh_Click()
- ' / -----------------------------------------------------------------------------------------------
- Call SGGridEmployeeBound(False)
- With SGGridEmployee
- .LeftCol = 0
- .SetFocus
- Sendkeys "{RIGHT}"
- End With
- txtSearch.Text = ""
- End Sub
- ' / -----------------------------------------------------------------------------------------------
- ' / เมื่อคลิ๊กที่ปุ่มค้นหา
- Private Sub cmdSearch_Click()
- ' / -----------------------------------------------------------------------------------------------
-
- ' / ตัดคำสงวน (Reserved Word) ที่มีปัญหากับฐานข้อมูลออกไป
- txtSearch.Text = Replace(txtSearch.Text, "'", "")
- txtSearch.Text = Replace(txtSearch.Text, "%", "")
- txtSearch.Text = Replace(txtSearch.Text, "*", "")
- If Trim(txtSearch.Text) = "" Or Len(txtSearch.Text) = 0 Then Exit Sub
-
- '/ ทำการค้นหาข้อมูล
- Call SGGridEmployeeBound(True)
-
- End Sub
- Private Sub txtSearch_KeyDown(KeyCode As Integer, Shift As Integer)
- If KeyCode = vbKeyDown Then Sendkeys "{TAB}"
- If KeyCode = vbKeyUp Then Sendkeys "+{TAB}"
- End Sub
- Private Sub txtSearch_KeyPress(KeyAscii As Integer)
- '// เกิดการกด Enter (ASCII Code มีค่าเท่ากับ 13 ฐาน 10)
- If KeyAscii = 13 Then
- Call cmdSearch_Click
- '// ปิดเสียงด้วยการกำหนดให้ KeyAscii = 0 หรือไม่มีการกดคีย์ใดๆ
- KeyAscii = 0
- End If
- End Sub
- Private Sub cmdRefresh_KeyDown(KeyCode As Integer, Shift As Integer)
- If KeyCode = vbKeyDown Or KeyCode = vbKeyRight Then Sendkeys "{TAB}"
- If KeyCode = vbKeyUp Or KeyCode = vbKeyLeft Then Sendkeys "+{TAB}"
- End Sub
- Private Sub Form_Resize()
- If Me.ScaleWidth < 120 Or Me.ScaleHeight < 120 Then Exit Sub
- fraData.Height = Me.ScaleHeight - 60
- fraData.Move 15, 0, Me.ScaleWidth - 15
- SGGridEmployee.Move 15, 615, fraData.Width - (SGGridEmployee.Left) - 15, fraData.Height - 690
- End Sub
- Private Sub Form_Unload(Cancel As Integer)
- On Error Resume Next
- If Dir$(App.Path & "\*.tmp") <> "" Then Kill App.Path & "\*.tmp"
- '/ ปิดการเชื่อมต่อกับฐานข้อมูล
- Call CloseDataBase
- End
- End Sub
คัดลอกไปที่คลิปบอร์ด
มาดูโค้ดในส่วนของโมดูลหากิน (modDataBase.bas)
- ' / -----------------------------------------------------------------------------------------------
- ' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
- ' / eMail : thongkorn@hotmail.com
- ' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
- ' / Facebook: https://www.facebook.com/g2gnet (For Thailand only)
- ' / Facebook: https://www.facebook.com/commonindy (World Wide)
- ' /
- ' / Purpose : Function to connect the MS Access DataBase.
- ' / Microsoft Visual Basic 6.0 Service Pack 6 + MS Access 2003
- ' / -----------------------------------------------------------------------------------------------
- Option Explicit
- '// ก่อนใช้งานต้องเลือก MDAC 2.8 มาจาก Project --> Refernces ก่อน
- Global ConnDB As New ADODB.Connection
- Global RS As New ADODB.Recordset ' / RecordSet หลัก
- Global DS As New ADODB.Recordset ' / RecordSet สำรอง
- Global RstData As New ADODB.Recordset ' / ใช้ในการพิมพ์รายงาน
- Global Statement As String
- Global SQLStmt As String
- ' / -----------------------------------------------------------------------------------------------
- Public Sub OpenDataBase()
- On Error GoTo Err_Handler
- Dim DB_File As String
- DB_File = App.Path
- If Right$(DB_File, 1) <> "" Then DB_File = DB_File & ""
- DB_File = DB_File & "DataBase.MDB"
- ' Open a connection.
- Set ConnDB = New ADODB.Connection
- ConnDB.ConnectionString = _
- "Provider=Microsoft.Jet.OLEDB.4.0;" & _
- "Data Source=" & DB_File & ";" & _
- "Persist Security Info=False"
- '" Jet OLEDB:Database Password=" & "password" & ";" '& _
- '" Engine Type=5;"
- ConnDB.Open
- Exit Sub
- Err_Handler:
- MsgBox "Open Database Error : " & vbCrLf & Err.Number & " " & Err.Description
- End
- End Sub
- Public Sub CloseDataBase()
- ' ตรวจสอบว่ามีการเชื่อมโยง - Connect ข้อมูลหรือไม่
- If ConnDB.State = adStateOpen Then
- ConnDB.Close
- Set ConnDB = Nothing
- End If
- End Sub
- ' / -----------------------------------------------------------------------------------------------
- ' / ฟังค์ชั่นแก้ไขในการ SendKeys ซึ่งใน Windows 8+ 64 บิท จะมีปัญหา
- Public Sub Sendkeys(Text As String, Optional Wait As Boolean = False)
- Dim WshShell As Object
- Set WshShell = CreateObject("Wscript.shell")
- WshShell.Sendkeys Text, Wait
- Set WshShell = Nothing
- End Sub
คัดลอกไปที่คลิปบอร์ด
Conclusion: ก็คงจะเห็นได้ชัดเจนว่า ทั้งแบบ Bound หรือ UnBound ต่างก็แสดงผลได้เหมือนกัน แต่วิธีการ UnBound Data เหมาะสมกับการนำข้อมูลมาเพื่อทำการแก้ไขในตัวตารางกริด หากเปรียบเทียบกับ VB.NET ก็คงเหมือนกับการใช้งาน Data Reader นั่นเอง
ดาวน์โหลดโค้ดต้นฉบับ VB6 + SharpGrid ได้ที่นี่
|
ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง
คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน
x
|