קוד עבור ProgressDialog ב-C#
-
אמנם יש דברים כבר קיימים ויש גם כאלה שמשתמשים בAPI של ווינדוס אבל מטעמים שונים לא הייתי מרוצה מהם ולכן עשיתי את הקוד דלהלן:
הקוד מציג את ההתקדמות על יד progressbar
ועל ידי הצגת התקדמות מתוך ה-maximum כטקסט
הקוד מציג גם את ההתקדמות באייקון בשורת המשימות
הקוד מציג את ההתקדמות גם בפעולות asyncהקוד הוא בגדר סקיצה ואשמח מאוד לקבל משוב:
using System; using System.Windows.Controls; using System.Windows; using System.Windows.Data; using System.Windows.Shell; namespace FullText.Controls { public static class ProgressDialog { public static IProgress<double> Start(string message, int maximum) { IProgress<double> reporter = null; Application.Current.Dispatcher.Invoke(() => { TextBlock textBlock = new TextBlock { Text = message, TextWrapping = TextWrapping.WrapWithOverflow, Margin = new Thickness(5), }; ProgressBar progressBar = new ProgressBar { Maximum = maximum}; TextBlock percentageTextBlock = new TextBlock { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center , Margin = new Thickness(1) }; Binding binding = new Binding("Value") { Source = progressBar, StringFormat = $"{{0:0}} \\ {maximum}" }; percentageTextBlock.SetBinding(TextBlock.TextProperty, binding); Grid grid = new Grid { Margin = new Thickness(5) }; grid.Children.Add(progressBar); grid.Children.Add(percentageTextBlock); StackPanel stackPanel = new StackPanel(); stackPanel.Children.Add(grid); stackPanel.Children.Add(textBlock); Window window = new Window { Content = stackPanel, SizeToContent = SizeToContent.WidthAndHeight, FlowDirection = FlowDirection.RightToLeft, Owner = Application.Current.MainWindow, ResizeMode = ResizeMode.CanMinimize }; TaskbarItemInfo taskbarItemInfo = new TaskbarItemInfo(); //Application.Current.MainWindow.TaskbarItemInfo = taskbarItemInfo; window.TaskbarItemInfo = taskbarItemInfo; taskbarItemInfo.ProgressState = TaskbarItemProgressState.Normal; reporter = new Progress<double>(OnProgressChanged); void OnProgressChanged(double incrementValue) { if (incrementValue == -1) { taskbarItemInfo.ProgressState = TaskbarItemProgressState.None; window.Close(); } //else if (progressBar.Value >= progressBar.Maximum) { window.Close(); taskbarItemInfo.ProgressState = TaskbarItemProgressState.None; } else { progressBar.Value += incrementValue; taskbarItemInfo.ProgressValue = (double)progressBar.Value / progressBar.Maximum; } } window.Show(); }); return reporter; } } }
צורת שימוש
התחלהvar progressReporter = ProgressReporter.Start($"מאנדקס את: {directoryToIndex}", files.Count);
התקדמות
progressReporter.Report(1);
סיום וסגירה
progressReporter.Report(-1);
-
הערה חשובה:
לאחר חקירת הנושא גיליתי שצריך לעבוד עם אחוזים ולא כמו שעשיתי
עיין כאן להסבר מפורט
https://brianlagunas.com/does-reporting-progress-with-task-run-freeze-your-wpf-ui/עריכה:
בדיקות שעשיתי יוצא שבעל הכתבה איננו צודק לא היה שום שיפור באחוזים לעומת מה שאני עשיתי
מה שכן מצאתי ששימוש ב- אפשרות של -Background ב-Dispathcer מועיל קימעאApplication.Current.Dispatcher.BeginInvoke(new Action(() => { }), DispatcherPriority.Background);
-
@pcinfogmach
אף אחד לא ניסה לטעון שדיווח באחוזים שונה מכל ערך מספרי אחר.
עיקר הנקודה שלו (וכנראה הטעות שלך) זו שורת הקוד הזאת:if (i % 1500 == 0)
זה תו אחוז של תכנות שמשמעותו מודולו, כלומר שארית של המספר הנוכחי בחלוקה ל1500, שבעצם זה אומר שכל פעם שזה אפס עברו 1500 פעימות. אין לזה קשר למושג אחוזים במובן המקובל (למרות שבמקרה גמור בדוגמה שלו הוא בחר להציג אחוזים).
הרעיון הוא לא לעדכן יותר מידי מהר את הUI, המאמר הזה מציג קוד שרירותי מידי וצריך לשנות אותו בהתאם למקרה ומה שצפוי להיות הזמן של כל פעימה. יותר גנרי ואלגנטי זה לעשות את זה עם טיימר של חצי שניה או 200 מילי שניות. -
@dovid כתב בקוד עבור ProgressDialog ב-C#:
הרעיון הוא לא לעדכן יותר מידי מהר את הUI, המאמר הזה מציג קוד שרירותי מידי וצריך לשנות אותו בהתאם למקרה ומה שצפוי להיות הזמן של כל פעימה. יותר גנרי ואלגנטי זה לעשות את זה עם טיימר של חצי שניה או 200 מילי שניות.
הוא אשר דיברתי לא ראיתי שום הבדל בין שני שיטות מצג עידכון ה-UI
הרעיון שלך עם טיימר לכאורה לא רלוונטי כאשר הזמן פעלה דינאמי כלומר כל פעימה זמנה משתנה תלוי בגודל קבצים וכיו"ב ואתה רוצה להציג את ההתקדמות בrealtimeכל זה אני כותב כשאלה!?
-
@pcinfogmach לא ראית הבדל כי אולי במקרה שלך אין שטף עדכונים, הוא מראה בחוש שיש הבדל.
תביא לי מקרה שיש בעיה, אשמח לטפל בו.
הרעיון שלי עם טיימר תמיד יעבוד כי הוא לא מתחשב במה השתנה אלא בכמה מהירות רוצים שהעין תתעדכן בשינויים. את הנתון על המצב הנוכחי זה ייקח ממשתנה שמתעדכן כל הזמן. -
@pcinfogmach כתב בקוד עבור ProgressDialog ב-C#:
הוא אשר דיברתי לא ראיתי שום הבדל בין שני שיטות מצג עידכון ה-UI
לא מדוייק שאתה אומר "הוא אשר דיברתי" בעוד כתבת שהוא סבור שיש לעדכן באחוזים ולא במספר מוחלט.
-
@dovid כתב בקוד עבור ProgressDialog ב-C#:
לא ראית הבדל כי אולי במקרה שלך אין שטף עדכונים, הוא מראה בחוש שיש הבדל.
עשיתי קוד בדיוק כמו שהוא עשה ולא ראיתי שום הבדל בשני השיטות בשניהם זה לא נתקע
אצלי זה נתקע בגלל שהיה הרבה קראות IO כך שלא היה נפ"מ באיזו תכיפות מעדכנים את ההתקדמות כי בזמן העדכון לרוב התוכנה היתה עסוקה בין כך. במקרה הזה מה שכתבתי למעלה להשתמש ב-dispatcher עזר לזה.