Group Blog
 
All Blogs
 
การโหลด Form มันเป็น Async!!!!

วันนี้อยากอัพเดทมาก ถึงแม้งานจะยุ่งแค่ไหน เพราะปัญหาที่เกิดขึ้นวันนี้มันน่าสนใจจริงๆ

โจทย์ที่พี่ Senior ทำในวันนี้คือต้องการให้มี Windows Form เล็กๆ โชว์ขึ้นมาก่อนโปรแกรมเริ่ม บอกว่าขณะนี้โปรแกรมหลักใกล้โหลดเสร็จหรือยัง ซึ่งวิธีการคือ

1. ตั้ง Event ใน Constructor ของ Form หลัก ว่าระหว่าง Load Constructor ให้ Update UI ของ FormProgress ที่แสดงอยู่ เพื่อความปลอดภัยเราก็ต้องเข้าไปทำบน UI Thread ของ FormProgress

Sample : Form1(FormProgress FormInstance)

{

.....

FormInstance.Dispatcher.Invoke(()=> FormProgress.Progress=2);

.....

FormInstance.Dispatcher.Invoke(()=>FormProgress.Progress=3);

}

แล้วในตัวทางเข้าของโปรแกรม ก็ตั้งไว้ว่า

Main()

{

Thread t=new Thread(new ThreadStart(()=>

{

FormProgress.Show()

var FormMain=new Form1(FormProgress) // โยน FormProgress เข้าไปให้ Constructor อัพเดทค่า

})); // แตก Thread ออกมาเพื่อทำการโหลด FormMain พร้อมกับแสดงฟอร์มนี้

}

เหมือนจะไม่มีอะไรผิดพลาด Thread UI ก็แตกออกมาถูกหมดแล้ว Managed ไว้หมดแล้ว ปรากฎว่าไม่มีอะไรเกิดขึ้นเลย แล้วโปรแกรมก็ค้างยาววววว

หลังจากค้นอยู่นาน ผมได้ข้อสรุปคือ สาเหตุนั้นเป็นเพราะ FormInstance.Show() เป็น ASYNCHRONUS METHOD!! เหลือเชื่อนะครับที่เมธอดที่เราใช้อยู่ทุกวันจะเป็น Async ได้โดยที่เราไม่รู้ตัว 

แล้วการที่มันเป็น Asynchronus Method แปลว่าอะไร ทำไมมันทำให้เราทำงานไม่ได้กันล่ะ ถ้าถามแบบนี้ เราจะลงลึกกันนิดนึงครับ

Asynchronus Method คือ Method ที่เราแค่เข้าไปสั่งให้มันทำ แต่ไม่ได้รอจนมันเสร็จ เช่น ถ้ามี Method ชื่อ WaitAndGetNumber() ถูกเขียนไว้ว่า

int a;

void WaitAndSetNumber()

{

Thread.Sleep(10000); //รอ 10 วินาที

a=200;

}

ถ้าเราเรียกใช้แบบ Sync

WaitAndSetNumber();

int b = 100;

การทำงานของมันจะเป็นว่า รอ 10 วินาที => ส่งค่า 200 ให้ a => กำหนด b เป็น 100

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

WaitAndSetNumberAsync();

int b=100;

Thread Main:สั่งให้เริ่มทำงาน => กำหนดให้ b เป็น 100

Thread 2: ถูกสั่งให้เริ่มทำ => รอ 10 วินาที => กำหนด a เป็น 200

บรรทัด b=100; จะทำต่อทันที เพราะบรรทัด WaitAndSetNumberAsync(); เป็นแค่การ "สั่งให้เริ่มทำ" ไม่ใช่การ "ให้ทำจนเสร็จ" การ "แค่สั่งให้เริ่มทำ แล้วลุยบรรทัดถัดไปทันทีโดยไม่รอให้เสร็จ" แบบนี้แหละครับที่เค้าเรียกกันว่า Asynchronus Method

ย้อนกลับมาที่ปัญหา ปัญหานี้หลังจากลองแล้วสามารถแก้ไขได้โดยเปลี่ยนจาก FormProgress.Show() เป็น FormProgress.ShowDialog() ซึ่งทำให้ผมสรุปว่า โครงสร้างภายในของ .Show() นั้นเป็น Asynchronus ซึ่งก็สอดคล้องกับที่ว่ามันเป็น non-modal form

อธิบายคือ .Show() นั้นจะไม่รอให้การวาดฟอร์มเสร็จ จะไปทำบรรทัดถัดไป new FormMain ทันที แล้วพอ FormMain พยายามจะเรียก Dispatcher ของ FormProgress ที่ยัง Show ไม่เสร็จ ทุกอย่างก็จะค้าง แต่พอเปลี่ยนมาใช้ ShowDialog() ซึ่งจะรอให้วาดฟอร์มเสร็จแล้วจึงทำงานบรรทัดถัดไป จึงสามารถมาเรียก Dispatcher ของ FormProgress ได้

ทั้งหมดนี่ไม่มีข้อมูลอ้างอิง ผมสันนิษฐานจากเหตุการณ์ที่เกิดขึ้นล้วนๆ อ่านใน MSDN ก็ไม่มีใครบอกว่า .Show() โครงสร้างภายในระหว่าง "วาด" มันทำบน Thread ใหม่ หรือทำบน Thread ที่เรียกใช้งานมันกันแน่ เพราะอันนี้เราเล่นแตก Thread แล้วใช้งานกันระหว่างวาดไม่เสร็จเลยทีเดียว





Create Date : 30 สิงหาคม 2555
Last Update : 30 สิงหาคม 2555 21:29:52 น. 0 comments
Counter : 486 Pageviews.

ชื่อ : * blog นี้ comment ได้เฉพาะสมาชิก
Comment :
  *ส่วน comment ไม่สามารถใช้ javascript และ style sheet
 

Valentine's Month


 
Mariel
Location :


[Profile ทั้งหมด]

ให้ทิปเจ้าของ Blog [?]
ฝากข้อความหลังไมค์
Rss Feed
Smember
ผู้ติดตามบล็อก : 1 คน [?]




Friends' blogs
[Add Mariel's blog to your web]
Links
 

 Pantip.com | PantipMarket.com | Pantown.com | © 2004 BlogGang.com allrights reserved.