locked
BackgroundWorker RRS feed

  • שאלה

  • שלום לכולם

    אני מנסה לאכלס  ObservableCollection מבסיס נתונים דרך  BackgroundWorker בשביל להשתמש בו כ - DataContext של החלון.
    קראתי הרבה מאמרים בנושא אך לא הצלחתי לקבל תשובה לבעיה הזאת (לפחות הצלחתי לייצר ProgressBar נורמלי סוף סוף...)

    האם יש למישהו רעיון?

    תודה רבה

    יום רביעי 01 פברואר 2012 13:18

תשובות

  • עקרונית, אפשר גם מThread אחר לעדכן אובייקטים שקשורים בDataBinding, היות וDataBinding ב WPF יודע לעבוד Thread-ים כשצריך, אבל אני אישית תמיד מרגיש לא נוח להשתמש בזה. BackgroundWorker פותר לנו את זה בצורה מלאה, ולפי דעתי זו אחת המחלקות היפות ביותר בדוט נט.

    כדוגמא, אם רוצים BackgroundWorker שיכול לעדכן את Collection ב UI, צריך ליצור אותו בדרך הבאה:

    1. ניצור את הXAML:

        <Grid>
            <ProgressBar Maximum="100" Height="29" HorizontalAlignment="Left" Margin="13,50,0,0" Name="progressBar1" VerticalAlignment="Top" Width="224" />
            <Button Content="Button" Height="25" HorizontalAlignment="Left" Margin="21,99,0,0" Name="button1" VerticalAlignment="Top" Width="88" Click="button1_Click" />
            <ListBox Height="127" HorizontalAlignment="Left" Margin="123,108,0,0" Name="listBox1" VerticalAlignment="Top" Width="124" ItemsSource="{Binding MyList}" />
        </Grid>
    

    שמנו כאן כפתור שיתחיל את הפעולה הארוכה, ProgressBar שיראה את ההתקדמות, וListBox שקשור לMyList - שיראה רשימה שמתעדכנת.

    2. ניצור ונאתחל את ה BackgroundWorker:

            BackgroundWorker bw;
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                bw = new BackgroundWorker();
    
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    
                bw.WorkerReportsProgress = true;
    
                bw.RunWorkerAsync();
            }
    

    המתודה המעניינת היא DoWork שבה נבצע את הפעולה הארוכה. שים לב כי זו פיסת הקוד *היחידה* שמתבצעת בThread אחר:

            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
                Thread.Sleep(200);
                bw.ReportProgress(10);
                Thread.Sleep(200);
                bw.ReportProgress(20);
                Thread.Sleep(200);
                bw.ReportProgress(30);
                Thread.Sleep(200);
                bw.ReportProgress(40);
                Thread.Sleep(200);
                bw.ReportProgress(50);
                Thread.Sleep(200);
                bw.ReportProgress(60);
                Thread.Sleep(200);
                bw.ReportProgress(70);
                Thread.Sleep(200);
                bw.ReportProgress(80);
                Thread.Sleep(200);
                bw.ReportProgress(90);
                Thread.Sleep(200);
                bw.ReportProgress(100);
            }
    
    

    Thread.Sleep סתם עוצר לחמישית שניה. ברגיל כאן היינו מבצעים את הקוד שלנו שלוקח הרבה זמן.
    bw.ReportProgress מאפשר לנו לדווח ל Thread של ה UI, ויגרום להרמה של ה Callback שנראה כך:

           void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                }
    

    וקיבלנו ProgressBar שבאמת מראה את השינויים שמתבצעים בת'רד אחר, ללא שום צורך בסינכרון ת'רדים או זהירות כלשהי.

    4. על מנת לעדכן גם מידע, ניצור פרופרטי שיחזיר את המידע שלנו, בצורה הבאה:

            public ObservableCollection<string> MyList { get; set; }
    
            public Window1()
            {
                InitializeComponent();
                
                MyList = new ObservableCollection<string>();
    
                this.DataContext = this;
            }
    

    וכך הListBox יציג את המידע שנמצא בו. כל מה שנותר עכשיו זה לשנות את DoWork, כך שלצד דיווח ה ProgressChanged הוא גם ישלח נתונים חדשים:

            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
    
                Thread.Sleep(200);
                bw.ReportProgress(10, "Ten");
                Thread.Sleep(200);
                bw.ReportProgress(20, "Twenty");
                Thread.Sleep(200);
                bw.ReportProgress(30, "Thirty");
                Thread.Sleep(200);
                bw.ReportProgress(40, "Fourty");
                Thread.Sleep(200);
                bw.ReportProgress(50, "Fifty");
                Thread.Sleep(200);
                bw.ReportProgress(60, "Sixty");
                Thread.Sleep(200);
                bw.ReportProgress(70, "Seventy");
                Thread.Sleep(200);
                bw.ReportProgress(80, "Eighty");
                Thread.Sleep(200);
                bw.ReportProgress(90, "Ninety");
                Thread.Sleep(200);
                bw.ReportProgress(100, "One Hundrend");
    
            }
    

    המתודה bw.ReportProgress מאפשרת לשלוח גם נתונים לצד אחוזי ההתקדמות, ואת זה אפשר לנצל על מנת לשלוח מידע חדש שהתקבל מהת'רד האחר.

    כל מה שנותר לנו זה להשתמש במידע הזה:

            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                
                MyList.Insert(0, e.UserState.ToString());
            }
    
    

    וקיבלנו הוספה בת'רד הנכון, ללא שום שימוש ב BeginInvoke או סנכרון ת'רדים שלנו!

     

    הקוד המלא נראה כך:
    XAML:

    <Window x:Class="WpfApplication2.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window1" Height="300" Width="300">
        <Grid>
            <ProgressBar Maximum="100" Height="29" HorizontalAlignment="Left" Margin="13,50,0,0" Name="progressBar1" VerticalAlignment="Top" Width="224" />
            <Button Content="Button" Height="25" HorizontalAlignment="Left" Margin="21,99,0,0" Name="button1" VerticalAlignment="Top" Width="88" Click="button1_Click" />
            <ListBox Height="127" HorizontalAlignment="Left" Margin="123,108,0,0" Name="listBox1" VerticalAlignment="Top" Width="124" ItemsSource="{Binding MyList}" />
        </Grid>
    </Window>
    


    CS:

        public partial class Window1 : Window
        {
            public ObservableCollection<string> MyList { get; set; }
    
            public Window1()
            {
                InitializeComponent();
                
                MyList = new ObservableCollection<string>();
    
                this.DataContext = this;
            }
            
            BackgroundWorker bw;
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                bw = new BackgroundWorker();
    
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    
                bw.WorkerReportsProgress = true;
    
                bw.RunWorkerAsync();
            }
    
            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                
                MyList.Insert(0, e.UserState.ToString());
            }
    
    
            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
    
                Thread.Sleep(200);
                bw.ReportProgress(10, "Ten");
                Thread.Sleep(200);
                bw.ReportProgress(20, "Twenty");
                Thread.Sleep(200);
                bw.ReportProgress(30, "Thirty");
                Thread.Sleep(200);
                bw.ReportProgress(40, "Fourty");
                Thread.Sleep(200);
                bw.ReportProgress(50, "Fifty");
                Thread.Sleep(200);
                bw.ReportProgress(60, "Sixty");
                Thread.Sleep(200);
                bw.ReportProgress(70, "Seventy");
                Thread.Sleep(200);
                bw.ReportProgress(80, "Eighty");
                Thread.Sleep(200);
                bw.ReportProgress(90, "Ninety");
                Thread.Sleep(200);
                bw.ReportProgress(100, "One Hundrend");
    
            }
        }
    










    • נערך על-ידי Elad R Katz יום ראשון 05 פברואר 2012 09:45
    • סומן כתשובה על-ידי Yoav Eyal יום שלישי 07 פברואר 2012 06:52
    יום ראשון 05 פברואר 2012 09:43

כל התגובות

  • זה פחות או יותר התנהגות הגיונית.

    ה-BackgroundWorker עושה Dispatching ל-EventHandlers כמו OnProrgess ו- OnCompleted. 

    אם אתה מנסה לשנות את הרשימה ב-Work אז זה קורה ב-Thread אחר.

    האופציה שלך היא או לאגור את המידע מקומית. ורק בסיום העבודה לעדכן את ה-OC ב-UI Thread

    או לעשות כל הזמן Dispatcher.BeginInvoke של פעולת ההשמה בלבד, כך שרק היא תתבצע ב- UI Thread.

    שים לב ש-BeginInvoke פעולה אסינכרונית, תזהר מאוד איך אתה מממש את הפעולות השונות.


    Ariel Ben Horesh | twitter: @arielbh blog: http://blogs.microsoft.co.il/blogs/arielbh/
    • נערך על-ידי ArielBH יום רביעי 01 פברואר 2012 15:30
    יום רביעי 01 פברואר 2012 15:29
  • מה הכוונה בתזהר מאוד?

    האם אתה מתכוון לבדיקת Exceptions?

    אשמח לדעת יותר

    יום חמישי 02 פברואר 2012 07:16
  • באופן תיאורטי שאתה עובד בסביבת multi threads, צריך להיות מאוד זהירים בשינוי של data בין threads, לדוגמא, דרך מקובלת אך כואבת בבחינת ביצועים היא שימוש ב-locks, כך שאתה שדואג שהשורה שממש משנה את הרשימה למשל לא תתבצע במקביל בשני threads ואז יהיה לך state לא תקין.

    בכל מקרה בנקודה הספיציפית הזאת, תשים לב ש-BeginInvoke לא קורה באופן מיידי, אלא מתוזמן ע"י ה-disptacher מתי שה-ui thread רץ.


    Ariel Ben Horesh | twitter: @arielbh blog: http://blogs.microsoft.co.il/blogs/arielbh/
    יום חמישי 02 פברואר 2012 07:25
  • עקרונית, אפשר גם מThread אחר לעדכן אובייקטים שקשורים בDataBinding, היות וDataBinding ב WPF יודע לעבוד Thread-ים כשצריך, אבל אני אישית תמיד מרגיש לא נוח להשתמש בזה. BackgroundWorker פותר לנו את זה בצורה מלאה, ולפי דעתי זו אחת המחלקות היפות ביותר בדוט נט.

    כדוגמא, אם רוצים BackgroundWorker שיכול לעדכן את Collection ב UI, צריך ליצור אותו בדרך הבאה:

    1. ניצור את הXAML:

        <Grid>
            <ProgressBar Maximum="100" Height="29" HorizontalAlignment="Left" Margin="13,50,0,0" Name="progressBar1" VerticalAlignment="Top" Width="224" />
            <Button Content="Button" Height="25" HorizontalAlignment="Left" Margin="21,99,0,0" Name="button1" VerticalAlignment="Top" Width="88" Click="button1_Click" />
            <ListBox Height="127" HorizontalAlignment="Left" Margin="123,108,0,0" Name="listBox1" VerticalAlignment="Top" Width="124" ItemsSource="{Binding MyList}" />
        </Grid>
    

    שמנו כאן כפתור שיתחיל את הפעולה הארוכה, ProgressBar שיראה את ההתקדמות, וListBox שקשור לMyList - שיראה רשימה שמתעדכנת.

    2. ניצור ונאתחל את ה BackgroundWorker:

            BackgroundWorker bw;
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                bw = new BackgroundWorker();
    
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    
                bw.WorkerReportsProgress = true;
    
                bw.RunWorkerAsync();
            }
    

    המתודה המעניינת היא DoWork שבה נבצע את הפעולה הארוכה. שים לב כי זו פיסת הקוד *היחידה* שמתבצעת בThread אחר:

            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
                Thread.Sleep(200);
                bw.ReportProgress(10);
                Thread.Sleep(200);
                bw.ReportProgress(20);
                Thread.Sleep(200);
                bw.ReportProgress(30);
                Thread.Sleep(200);
                bw.ReportProgress(40);
                Thread.Sleep(200);
                bw.ReportProgress(50);
                Thread.Sleep(200);
                bw.ReportProgress(60);
                Thread.Sleep(200);
                bw.ReportProgress(70);
                Thread.Sleep(200);
                bw.ReportProgress(80);
                Thread.Sleep(200);
                bw.ReportProgress(90);
                Thread.Sleep(200);
                bw.ReportProgress(100);
            }
    
    

    Thread.Sleep סתם עוצר לחמישית שניה. ברגיל כאן היינו מבצעים את הקוד שלנו שלוקח הרבה זמן.
    bw.ReportProgress מאפשר לנו לדווח ל Thread של ה UI, ויגרום להרמה של ה Callback שנראה כך:

           void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                }
    

    וקיבלנו ProgressBar שבאמת מראה את השינויים שמתבצעים בת'רד אחר, ללא שום צורך בסינכרון ת'רדים או זהירות כלשהי.

    4. על מנת לעדכן גם מידע, ניצור פרופרטי שיחזיר את המידע שלנו, בצורה הבאה:

            public ObservableCollection<string> MyList { get; set; }
    
            public Window1()
            {
                InitializeComponent();
                
                MyList = new ObservableCollection<string>();
    
                this.DataContext = this;
            }
    

    וכך הListBox יציג את המידע שנמצא בו. כל מה שנותר עכשיו זה לשנות את DoWork, כך שלצד דיווח ה ProgressChanged הוא גם ישלח נתונים חדשים:

            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
    
                Thread.Sleep(200);
                bw.ReportProgress(10, "Ten");
                Thread.Sleep(200);
                bw.ReportProgress(20, "Twenty");
                Thread.Sleep(200);
                bw.ReportProgress(30, "Thirty");
                Thread.Sleep(200);
                bw.ReportProgress(40, "Fourty");
                Thread.Sleep(200);
                bw.ReportProgress(50, "Fifty");
                Thread.Sleep(200);
                bw.ReportProgress(60, "Sixty");
                Thread.Sleep(200);
                bw.ReportProgress(70, "Seventy");
                Thread.Sleep(200);
                bw.ReportProgress(80, "Eighty");
                Thread.Sleep(200);
                bw.ReportProgress(90, "Ninety");
                Thread.Sleep(200);
                bw.ReportProgress(100, "One Hundrend");
    
            }
    

    המתודה bw.ReportProgress מאפשרת לשלוח גם נתונים לצד אחוזי ההתקדמות, ואת זה אפשר לנצל על מנת לשלוח מידע חדש שהתקבל מהת'רד האחר.

    כל מה שנותר לנו זה להשתמש במידע הזה:

            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                
                MyList.Insert(0, e.UserState.ToString());
            }
    
    

    וקיבלנו הוספה בת'רד הנכון, ללא שום שימוש ב BeginInvoke או סנכרון ת'רדים שלנו!

     

    הקוד המלא נראה כך:
    XAML:

    <Window x:Class="WpfApplication2.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window1" Height="300" Width="300">
        <Grid>
            <ProgressBar Maximum="100" Height="29" HorizontalAlignment="Left" Margin="13,50,0,0" Name="progressBar1" VerticalAlignment="Top" Width="224" />
            <Button Content="Button" Height="25" HorizontalAlignment="Left" Margin="21,99,0,0" Name="button1" VerticalAlignment="Top" Width="88" Click="button1_Click" />
            <ListBox Height="127" HorizontalAlignment="Left" Margin="123,108,0,0" Name="listBox1" VerticalAlignment="Top" Width="124" ItemsSource="{Binding MyList}" />
        </Grid>
    </Window>
    


    CS:

        public partial class Window1 : Window
        {
            public ObservableCollection<string> MyList { get; set; }
    
            public Window1()
            {
                InitializeComponent();
                
                MyList = new ObservableCollection<string>();
    
                this.DataContext = this;
            }
            
            BackgroundWorker bw;
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                bw = new BackgroundWorker();
    
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    
                bw.WorkerReportsProgress = true;
    
                bw.RunWorkerAsync();
            }
    
            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                
                MyList.Insert(0, e.UserState.ToString());
            }
    
    
            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
    
                Thread.Sleep(200);
                bw.ReportProgress(10, "Ten");
                Thread.Sleep(200);
                bw.ReportProgress(20, "Twenty");
                Thread.Sleep(200);
                bw.ReportProgress(30, "Thirty");
                Thread.Sleep(200);
                bw.ReportProgress(40, "Fourty");
                Thread.Sleep(200);
                bw.ReportProgress(50, "Fifty");
                Thread.Sleep(200);
                bw.ReportProgress(60, "Sixty");
                Thread.Sleep(200);
                bw.ReportProgress(70, "Seventy");
                Thread.Sleep(200);
                bw.ReportProgress(80, "Eighty");
                Thread.Sleep(200);
                bw.ReportProgress(90, "Ninety");
                Thread.Sleep(200);
                bw.ReportProgress(100, "One Hundrend");
    
            }
        }
    










    • נערך על-ידי Elad R Katz יום ראשון 05 פברואר 2012 09:45
    • סומן כתשובה על-ידי Yoav Eyal יום שלישי 07 פברואר 2012 06:52
    יום ראשון 05 פברואר 2012 09:43
  • תודה רבה על ההשקעה בכתיבה ובהסבר!!!

    זה עזר לי מאוד

    יום שלישי 07 פברואר 2012 06:56
  • עקרונית, אפשר גם מThread אחר לעדכן אובייקטים שקשורים בDataBinding, היות וDataBinding ב WPF יודע לעבוד Thread-ים כשצריך, אבל אני אישית תמיד מרגיש לא נוח להשתמש בזה. BackgroundWorker פותר לנו את זה בצורה מלאה, ולפי דעתי זו אחת המחלקות היפות ביותר בדוט נט.

    כדוגמא, אם רוצים BackgroundWorker שיכול לעדכן את Collection ב UI, צריך ליצור אותו בדרך הבאה:

    1. ניצור את הXAML:

        <Grid>
            <ProgressBar Maximum="100" Height="29" HorizontalAlignment="Left" Margin="13,50,0,0" Name="progressBar1" VerticalAlignment="Top" Width="224" />
            <Button Content="Button" Height="25" HorizontalAlignment="Left" Margin="21,99,0,0" Name="button1" VerticalAlignment="Top" Width="88" Click="button1_Click" />
            <ListBox Height="127" HorizontalAlignment="Left" Margin="123,108,0,0" Name="listBox1" VerticalAlignment="Top" Width="124" ItemsSource="{Binding MyList}" />
        </Grid>
    

    שמנו כאן כפתור שיתחיל את הפעולה הארוכה, ProgressBar שיראה את ההתקדמות, וListBox שקשור לMyList - שיראה רשימה שמתעדכנת.

    2. ניצור ונאתחל את ה BackgroundWorker:

            BackgroundWorker bw;
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                bw = new BackgroundWorker();
    
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    
                bw.WorkerReportsProgress = true;
    
                bw.RunWorkerAsync();
            }
    

    המתודה המעניינת היא DoWork שבה נבצע את הפעולה הארוכה. שים לב כי זו פיסת הקוד *היחידה* שמתבצעת בThread אחר:

            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
                Thread.Sleep(200);
                bw.ReportProgress(10);
                Thread.Sleep(200);
                bw.ReportProgress(20);
                Thread.Sleep(200);
                bw.ReportProgress(30);
                Thread.Sleep(200);
                bw.ReportProgress(40);
                Thread.Sleep(200);
                bw.ReportProgress(50);
                Thread.Sleep(200);
                bw.ReportProgress(60);
                Thread.Sleep(200);
                bw.ReportProgress(70);
                Thread.Sleep(200);
                bw.ReportProgress(80);
                Thread.Sleep(200);
                bw.ReportProgress(90);
                Thread.Sleep(200);
                bw.ReportProgress(100);
            }
    
    

    Thread.Sleep סתם עוצר לחמישית שניה. ברגיל כאן היינו מבצעים את הקוד שלנו שלוקח הרבה זמן.
    bw.ReportProgress מאפשר לנו לדווח ל Thread של ה UI, ויגרום להרמה של ה Callback שנראה כך:

           void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                }
    

    וקיבלנו ProgressBar שבאמת מראה את השינויים שמתבצעים בת'רד אחר, ללא שום צורך בסינכרון ת'רדים או זהירות כלשהי.

    4. על מנת לעדכן גם מידע, ניצור פרופרטי שיחזיר את המידע שלנו, בצורה הבאה:

            public ObservableCollection<string> MyList { get; set; }
    
            public Window1()
            {
                InitializeComponent();
                
                MyList = new ObservableCollection<string>();
    
                this.DataContext = this;
            }
    

    וכך הListBox יציג את המידע שנמצא בו. כל מה שנותר עכשיו זה לשנות את DoWork, כך שלצד דיווח ה ProgressChanged הוא גם ישלח נתונים חדשים:

            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
    
                Thread.Sleep(200);
                bw.ReportProgress(10, "Ten");
                Thread.Sleep(200);
                bw.ReportProgress(20, "Twenty");
                Thread.Sleep(200);
                bw.ReportProgress(30, "Thirty");
                Thread.Sleep(200);
                bw.ReportProgress(40, "Fourty");
                Thread.Sleep(200);
                bw.ReportProgress(50, "Fifty");
                Thread.Sleep(200);
                bw.ReportProgress(60, "Sixty");
                Thread.Sleep(200);
                bw.ReportProgress(70, "Seventy");
                Thread.Sleep(200);
                bw.ReportProgress(80, "Eighty");
                Thread.Sleep(200);
                bw.ReportProgress(90, "Ninety");
                Thread.Sleep(200);
                bw.ReportProgress(100, "One Hundrend");
    
            }
    

    המתודה bw.ReportProgress מאפשרת לשלוח גם נתונים לצד אחוזי ההתקדמות, ואת זה אפשר לנצל על מנת לשלוח מידע חדש שהתקבל מהת'רד האחר.

    כל מה שנותר לנו זה להשתמש במידע הזה:

            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                
                MyList.Insert(0, e.UserState.ToString());
            }
    
    

    וקיבלנו הוספה בת'רד הנכון, ללא שום שימוש ב BeginInvoke או סנכרון ת'רדים שלנו!

     

    הקוד המלא נראה כך:
    XAML:

    <Window x:Class="WpfApplication2.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window1" Height="300" Width="300">
        <Grid>
            <ProgressBar Maximum="100" Height="29" HorizontalAlignment="Left" Margin="13,50,0,0" Name="progressBar1" VerticalAlignment="Top" Width="224" />
            <Button Content="Button" Height="25" HorizontalAlignment="Left" Margin="21,99,0,0" Name="button1" VerticalAlignment="Top" Width="88" Click="button1_Click" />
            <ListBox Height="127" HorizontalAlignment="Left" Margin="123,108,0,0" Name="listBox1" VerticalAlignment="Top" Width="124" ItemsSource="{Binding MyList}" />
        </Grid>
    </Window>
    


    CS:

        public partial class Window1 : Window
        {
            public ObservableCollection<string> MyList { get; set; }
    
            public Window1()
            {
                InitializeComponent();
                
                MyList = new ObservableCollection<string>();
    
                this.DataContext = this;
            }
            
            BackgroundWorker bw;
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                bw = new BackgroundWorker();
    
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    
                bw.WorkerReportsProgress = true;
    
                bw.RunWorkerAsync();
            }
    
            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;
                
                MyList.Insert(0, e.UserState.ToString());
            }
    
    
            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
    
                Thread.Sleep(200);
                bw.ReportProgress(10, "Ten");
                Thread.Sleep(200);
                bw.ReportProgress(20, "Twenty");
                Thread.Sleep(200);
                bw.ReportProgress(30, "Thirty");
                Thread.Sleep(200);
                bw.ReportProgress(40, "Fourty");
                Thread.Sleep(200);
                bw.ReportProgress(50, "Fifty");
                Thread.Sleep(200);
                bw.ReportProgress(60, "Sixty");
                Thread.Sleep(200);
                bw.ReportProgress(70, "Seventy");
                Thread.Sleep(200);
                bw.ReportProgress(80, "Eighty");
                Thread.Sleep(200);
                bw.ReportProgress(90, "Ninety");
                Thread.Sleep(200);
                bw.ReportProgress(100, "One Hundrend");
    
            }
        }
    










    שלום אלעד, אני יודע שעבר הרבה זמן מאז שכתבת את ההודעה הנ"ל אבל הגעתי אליה ואני במצב ממש קריטי וחייב עזרה.

    ניסיתי לעשות מה שהסברת אבל מאחר ויש לי צורך לעדכן כמה רכיבים שונים השתמשתי במספר של העדכון כבורר. זאת אומרת שאני שולח התקדמות עם מספר + האוביקט ובפעולה של שינוי לפי המספר אני יודע איזה אובייקט עלי לשנות.

    משום בכל הרצה אני מקבל תוצאה שונה בUI יש לך רעיון למה זה קורה?

    יום חמישי 08 מאי 2014 17:25