קצת היה לי קשה לכתוב את הכותרת בעברית. כאשר אנחנו כותבים אפליקצייה כלשהי, או קליינט ב WPF (רצוי) או WINFORMS אז לרוב אנחנו צריכים לעדכן פקדים ב GUI שלנו (כמו Progress Bar או תוויות טקסט שונות, או כל דבר אחר). אני לפעמים רואה מתכנתים שקצת "מסתבכים" עם זה ועושים זאת בדרכים "עקיפות" וקצת מסובכות.
אני אציג את הפתרון שלדעתי הוא הפתרון הנכון.
בניתי טופס לדוגמא ב WPF (קצת מכוער אבל רק בשביל הדוגמא) שמכיל כפתור, תווית טקסט ו Progress Bar:
ה"אפליקצייה" המדהימה עושה את הבא: בעת לחיצה על הכפתור, יופעל Thread שמפעיל פונקציה כלשהי (במקרה שלנו היא "מורידה קבצים" מהשרת. כל מה שהפונקציה רוצה זה לעדכן את ה ProgressBar, ולעדכן ב GUI את שם הקובץ שיורד כרגע.
ניצור ב class של הטופס EventHandler שמקבל GuiEventArgs:
וכמובן ניצור GuiEventArgs ונכניס בו את כל הפרמטרים שאנחנו רוצים להעביר בהודעה ל GUI:
בפונקציה שלנו אנחנו נרשמים ל Event עם הפונקציה שאנחנו רוצים שתורץ כאשר ה Event מופעל, ולאחר מכן אנחנו מפעילים את ה Event עם הערכים שאנחנו רוצים לשלוח לטופס:
ה Event מריץ את הפונקציה הבאה:
אם היינו כותבים ב WINFORMS אז ההבדל היחידי היה שבפונקציה הנ"ל היה Invoke((Action) ללא ה Dispatcher.
הסבר קצר:
ה Dispatcher הוא סוג של "תור" שמקבל בקשות, ואחראי לשלוח את הבקשות על פי עדיפות. במקרה שלנו הוא שולח את הבקשה ל Thread הראשי של ה GUI, וזה מאפשר לנו בקלות לעדכן ערכים בפקדים שנמצאים ב GUI מ Thread נפרד
אני אציג את הפתרון שלדעתי הוא הפתרון הנכון.
בניתי טופס לדוגמא ב WPF (קצת מכוער אבל רק בשביל הדוגמא) שמכיל כפתור, תווית טקסט ו Progress Bar:
ה"אפליקצייה" המדהימה עושה את הבא: בעת לחיצה על הכפתור, יופעל Thread שמפעיל פונקציה כלשהי (במקרה שלנו היא "מורידה קבצים" מהשרת. כל מה שהפונקציה רוצה זה לעדכן את ה ProgressBar, ולעדכן ב GUI את שם הקובץ שיורד כרגע.
private void buttonStart_Click(object sender, EventArgs e)
{
Thread SomeThread = new Thread(foo);
SomeThread.Start();
}
public event EventHandlermsgRecieved;
public class GuiEventArgs : EventArgs
{
public int Progress { get; set; }
public string DownloadedFile { get; set; }
public GuiEventArgs(int progress, string downloadedFile)
{
Progress = progress;
DownloadedFile = downloadedFile;
}
}
void foo()
{
//initialize the value for progressbar
int progressValue = 10;
while (true)
{
//sign to the event
msgRecieved += new EventHandler(MainWindow_msgRecieved);
//invoke the event
msgRecieved.Invoke(new object(), new GuiEventArgs(progressValue,"Any name"));
progressValue += 10;
Thread.Sleep(100);
}
}
void MainWindow_msgRecieved(object sender, GuiEventArgs e)
{
Dispatcher.Invoke((Action)(() =>
{
progressBar1.Value = e.Progress;
labelDownloadingFile.Content = e.DownloadedFile;
}));
}
אם היינו כותבים ב WINFORMS אז ההבדל היחידי היה שבפונקציה הנ"ל היה Invoke((Action) ללא ה Dispatcher.
הסבר קצר:
ה Dispatcher הוא סוג של "תור" שמקבל בקשות, ואחראי לשלוח את הבקשות על פי עדיפות. במקרה שלנו הוא שולח את הבקשה ל Thread הראשי של ה GUI, וזה מאפשר לנו בקלות לעדכן ערכים בפקדים שנמצאים ב GUI מ Thread נפרד

אין תגובות:
הוסף רשומת תגובה