משיב מוביל
עזרה עם BackgroundWorker בשימוש עם MVVM

שאלה
-
יש לי בעיה שאני פשוט לא מצליח להבין.
(יש לציין כי הקוד עובד מצויין ללא ה BackgroudWorker כך שזו לא הבעיה, הבעיה החלה כשניסיתי להטמיע אותו)
תחילה אסביר את המבנה של הפרויקט שלי (הוא מסובך מאוד - פרויקט גמר לתואר ראשון בהנדסת תוכנה):
הXAML שלי מכיל:
<NetworkUI:NetworkView x:Name="networkControl" NodesSource="{Binding Network.Nodes}" ConnectionsSource="{Binding Path=Network.Connections}" MouseDown="networkControl_MouseDown" MouseUp="networkControl_MouseUp" MouseMove="networkControl_MouseMove" />
כאשר הNetwork הוא אובייקט שנמצא בViewModel של החלון הנ"ל.
את המידע אני מקבל מDATABASE (ומקבל נכון) ולאחר מכן מנסה לשייך את המידע לתוך אובייקטים בתוך הNetwork.
הConstructor של הViewModel:
public MainWindowViewModel() { Network = new NetworkViewModel(); nodes = new List<NodeViewModel>(); bw = new BackgroundWorker(); bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); bw.RunWorkerAsync(false); }
הDoWork ו WorkCompleted:
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => this.IsBusy = false)); this.IsBusy = false; Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => OnPropertyChanged("Network"))); } void bw_DoWork(object sender, DoWorkEventArgs e) { //Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => )); //Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => )); this.BusyContent = "Please Wait..."; this.IsBusy = true; ShowSystem((bool)e.Argument); }
והפונקציה המרכזית היא ShowSystem, היא מאוד ארוכה אני ארשום את החלק שמכניס לUI:
#region addNodesToUi //Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => )); try { //Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => )); Debug.WriteLine("Success creating new nodeViewModel"); } catch (Exception ex) { logger.addMessage("Error in creating new nodeViewModel " + ex.Message + " Inner: " + ex.InnerException.Message); Debug.WriteLine("Error in creating new nodeViewModel " + ex.Message + " Inner: " + ex.InnerException.Message); } int width = 0; int height = 0; foreach (var system in MainNet.Systems) { Debug.WriteLine("inside Foreach in system: " + system.Name + " interface " + system.Interfaces.Count + " structs " + system.Structs.Count); if (nodes == null) Debug.WriteLine("FUUUCCKKKK!"); try { Debug.WriteLine("Before add node"); try { Debug.WriteLine("trying to add: " + system.Name + " " + system.InputNum + " " + system.OutputNum + " " + system.Interfaces.Count + " " + system.Enums.Count + " " + system.Structs.Count); Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => nodes.Add(CreateNode(system.Name, new Point(width, height), false, system.InputNum, system.OutputNum, system.Interfaces, system.Enums, system.Structs, update)))); } catch (Exception ex) { logger.addMessage("Error adding new node to list " + ex.Message + " Inner: " + ex.InnerException.Message); Debug.WriteLine("Error adding new node to list " + ex.Message + " Inner: " + ex.InnerException.Message); } Debug.WriteLine("Success adding new node to list"); } catch (Exception ex) { logger.addMessage("Error in adding new node to list " + ex.Message + " Inner: " + ex.InnerException.Message); Debug.WriteLine("Error in adding new node to list " + ex.Message + " Inner: " + ex.InnerException.Message); } width += 150; if (width >= 700) { width = 0; height += 100; } } if (MainWindow.IsFlow) { Object[] getInterfacesWithGuidToFlowParam = new Object[1]; getInterfacesWithGuidToFlowParam[0] = MainWindow.GuidToFlow; try { interfacesForFlow = (List<String>)getInterfacesWithGuidToFlow.Invoke(sqlDB, getInterfacesWithGuidToFlowParam); Debug.WriteLine("Success getInterfacesWithGuidToFlow " + interfacesForFlow.Count); } catch (Exception ex) { logger.addMessage("Error in getInterfacesWithGuidToFlow : " + ex.Message + " Inner: " + ex.InnerException.Message); Debug.WriteLine("Error in getInterfacesWithGuidToFlow : " + ex.Message + " Inner: " + ex.InnerException.Message); } } foreach (var system in MainNet.Systems) { if (system.OutputNum > 0) //this system has an output connector { int i = 0; foreach (var outId in system.Outputs) //loop throw all systems ids that current system is connected to { Debug.WriteLine("out id = " + outId); ConnectionViewModel connection = null; try { Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => connection = new ConnectionViewModel())); Debug.Write("Success creating new ConnectionViewModel"); } catch (Exception ex) { logger.addMessage("Error in creating new ConnectionViewModel " + ex.Message + " Inner: " + ex.InnerException.Message); Debug.WriteLine("Error in creating new ConnectionViewModel " + ex.Message + " Inner: " + ex.InnerException.Message); } Object[] getSystemNameParams = new Object[1]; getSystemNameParams[0] = outId; string destSystemName = ""; try { destSystemName = (String)getSystemName.Invoke(sqlDB, getSystemNameParams); } catch (Exception ex) { logger.addMessage("Error in getSystemName: " + ex.Message + " Inner: " + ex.InnerException.Message); Debug.WriteLine("Error in getSystemName: " + ex.Message + " Inner: " + ex.InnerException.Message); } NodeViewModel sourceItem = null; NodeViewModel destItem = null; Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => sourceItem = nodes.Find(x => x.Name == system.Name))); //int sourceId = nodes.FindIndex(sourceItem); Debug.Write("Success creating new sourceItem"); Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => destItem = nodes.Find(x => x.Name == destSystemName))); Debug.Write("Success creating new destItem"); try { Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => destItem.InputSystems.Add(sourceItem.Name))); } catch (Exception ex) { logger.addMessage("Error adding input system: " + ex.Message); Debug.Write("Error adding input system: " + ex.Message); } try { Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => sourceItem.OutputSystems.Add(destItem.Name))); } catch (Exception ex) { logger.addMessage("Error adding OutputSystems: " + ex.Message); Debug.Write("Error adding OutputSystems: " + ex.Message); } Debug.Write("Success bah"); //int destId = nodes.FindIndex(destItem); Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => connection.SourceConnector = sourceItem.OutputConnectors[i++])); Debug.Write("Success bah"); Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => connection.DestConnector = destItem.InputConnectors[destItem.InputConnectors.Count - 1])); Debug.Write("Success bah"); // Add the connection to the view-model. // Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => connection.Type = ConnectionViewModel.ConnectorType.REGULAR)); Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => this.Network.Connections.Add(connection))); //Debug.Write("Success bah"); if (MainWindow.IsFlow) { Debug.WriteLine("inside IsFlow!"); foreach (var @interface in interfacesForFlow) { String[] systems = @interface.Split('_'); Debug.WriteLine("Flow from: " + systems[0] + " To " + systems[1]); if(systems[0].Equals(sourceItem.Name) && systems[1].Equals(destItem.Name)) Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => connection.Type = ConnectionViewModel.ConnectorType.FLOW)); } } } } } #endregion
כמו שרואים אני משתמש בDispacher על מנת לבצע את כל הפעולות שקשורות לcollections שיש להם Bindings.
מה שקורה כרגע זה שה BusyIndicator מופיע בזמן שכל המידע מיובא מבסיס הנתונים, לאחר שכל המידע מתקבל (ללא שום exception) ה Indicator יורד (מה שמצביע על כך שה Worker סיים את עבודתו) אבל...הרכיבי UI שהיו אמורים להופיע פשוט לא שם..כאילו חסר איזה refresh
ממש אשמח לעזרה אני כבר אובד עצות
יום חמישי 08 מאי 2014 14:18
תשובות
-
שלום, מה זאת אומרת רכיבי UI לא שם. אני מניח שאתה מתכוון לNotes? 1. האם ווידאת כי הרכיבים מתמלאים? 2. יש לך יותר מידי קריאות לDispatcher לדעתי, האם באמת יש בכך צורך? עשיתי דוגמא קטנה MVVM + BefinWorker אשר ממלא נתונים לטבלה, וזה ממלא כנדרש.. להלן לינק לדוגמא שעשיתי - אולי היא תעזור לך עם הקוד שלך.. http://pastebin.com/uH4qAHnW אם יהיו לך שאלות, תוכל לשאול כאן ונמשיך.
- סומן כתשובה על-ידי Eran Sharvit שבת 07 יוני 2014 15:42
יום רביעי 28 מאי 2014 13:21
כל התגובות
-
מצערים על העיכוב בתגובה. בקרוב מומחי הקהילה ינסו לסייע. אם בינתיים מצאת פתרון - אנא עדכן אותנו.
תודה.
מיקרוסופט מציעה שירות זה ללא תשלום, למטרת סיוע למשתמשים והעשרת הידע הקשור בטכנולוגיות ובמוצרים של מיקרוסופט. תוכן זה מתפרסם כפי שהוא והוא אינו מעיד על כל אחריות מצד מיקרוסופט.
יום שלישי 13 מאי 2014 08:54 -
שלום, מה זאת אומרת רכיבי UI לא שם. אני מניח שאתה מתכוון לNotes? 1. האם ווידאת כי הרכיבים מתמלאים? 2. יש לך יותר מידי קריאות לDispatcher לדעתי, האם באמת יש בכך צורך? עשיתי דוגמא קטנה MVVM + BefinWorker אשר ממלא נתונים לטבלה, וזה ממלא כנדרש.. להלן לינק לדוגמא שעשיתי - אולי היא תעזור לך עם הקוד שלך.. http://pastebin.com/uH4qAHnW אם יהיו לך שאלות, תוכל לשאול כאן ונמשיך.
- סומן כתשובה על-ידי Eran Sharvit שבת 07 יוני 2014 15:42
יום רביעי 28 מאי 2014 13:21 -
הי YogevNisim
האם יש עדכון בסטטוס השאלה? האם בדקת את מה שהציע David?
מיקרוסופט מציעה שירות זה ללא תשלום, למטרת סיוע למשתמשים והעשרת הידע הקשור בטכנולוגיות ובמוצרים של מיקרוסופט. תוכן זה מתפרסם כפי שהוא והוא אינו מעיד על כל אחריות מצד מיקרוסופט.
יום ראשון 01 יוני 2014 11:05 -
היי,
לא יודע אם זה עדיין רלוונטי, אבל אולי זה יעזור לאחרים שיראו את השאלה.
הבעיה נובעת מכך שה-Binding מתבצע מול List במקום מול ObservableCollection, מה שאומר שהכנסת איברים לרשימה לא תקפיץ את האירוע CollectionChanged, ולכן ה-UI לא מתעדכן בהתאם (למרות שהמודל מעודכן).
יש לא מעט מעקפים לכך, אבל הדרך הנכונה ביותר היא לבצע את ה-Binding מול ObservableCollection ולא List.
אופיר מקמל.
יום שני 28 יולי 2014 11:22