locked
"It is not valid to call Execute() on a different Dispatcher than the ExecutableObject's Logic Dispatcher."

    Question

  • I am currently encountering a new issue that I am looking help for 

    When I tried to use the code suggested by Justin 

     

     IEnumerable<Attendence> attendence = this.DataWorkspace.ApplicationData.Attendences.Where(a => a.SubjectId == this.Subject.Id).Execute();
     result = attendence.Select(a => a.AttendenceDate).Distinct().Count();
    In a screen's button execution code, I get following error

    "It is not valid to call Execute() on a different Dispatcher than the ExecutableObject's Logic Dispatcher."

    I understand this is a issue related with 2 threads available in LS screens but I believe there should be a very simple technique available to accomplish this at the button's execution code.

    If thats not the case I will be interested in knowing how would be possible for me to handle this error.

    Thanks again in Advance :)
    Regards





    Supreet
    Friday, May 13, 2011 1:01 PM

Answers

  • You should be calling BeginInvoke instead of BeginInlineInvoke.
    Justin Anderson, LightSwitch Development Team
    • Marked as answer by Supreet tare Saturday, May 14, 2011 2:27 PM
    Saturday, May 14, 2011 10:52 AM
  • Looks like you are running this code in a ControlAvailable event handler.

    Your problem is that you are trying to interact with Silverlight UI (objects owned by the main thread) and LightSwitch data (objects owned by a logical thread) interspersed in your code.

    I think you should perform a BeginInvoke immediately on the dispatcher of the screen (like you have in the code that you posted) and perform all of your querying immediately in the beginning of that. Then perform a BeginInvoke on the main dispatcher within the BeginInvoke of the screen's dispatcher into order to get the data grid control reference and set its ItemsSource property.

    If what you are trying to do is perform some kind of transform on your data to display it in some kind of aggregated way, I think a better solution is to refactor your entity schema in a more normalized way that enables this. That way, you wouldn't need to create a custom control and write a lot of code to just display it.


    Justin Anderson, LightSwitch Development Team
    • Marked as answer by Supreet tare Saturday, May 14, 2011 2:27 PM
    Saturday, May 14, 2011 7:42 AM
  • Hi Justin,

       Thanks it worked like a charm, the only thing I am left with is that even after creating an observable collection (which has 6 records in it ) & binding it with the grid I am not able to see the control on the UI.

    Is it possible to 

    1. Create a custom Control having a silverlight grid

    2. Find that SL grid in code & bind it to the collection

    It should work?

    Please point me to any correct implementations you may be aware of.

    Thanks & Regards

    Supreet


    UPDATE: AutoGenerateColumns="true" solved this problem, I can see my grid on the screen now..
    • Edited by Supreet tare Sunday, May 15, 2011 5:37 AM Updated with Answer found
    • Marked as answer by Supreet tare Sunday, May 15, 2011 5:37 AM
    Saturday, May 14, 2011 2:30 PM

All replies

  • UPDATE: 

    As Yann Suggested i need to wrap my code inside  this.Details.Dispatcher.BeginInvoke(() =>);

    But this yields another issue:

     

    The problem is I have a lot of code written where I am using this attendance object so I can not keep that rest of the code outside this wrapper else this object (attendance) will not be available for my rest of the code.

    When I try putting my entire code inside this wrapper I start getting 

    "Invalid cross-thread access." Error?

    Any thing I can do to work this?

     

    P.S. Some portion of this thread has been continued from 2nd part of this thread here

    http://social.msdn.microsoft.com/Forums/en-US/lightswitchgeneral/thread/40e73c56-a580-40f1-8527-ef0bb756b380/

    Thanks & Regards

     


    Supreet
    • Edited by Supreet tare Friday, May 13, 2011 1:39 PM Linked related thread
    Friday, May 13, 2011 1:03 PM
  • Supreet,

    Can you assign it to a variable outside the wrapper, & use it both inside & outside it?

    If not, you'll need to give us an example of the code that's not working.

    It's probably a good idea to include a link here to the original post, so that people can follow what your problem was.

    Yann

    Friday, May 13, 2011 1:06 PM
  • Hi Yann,  

       Thanks for your response. Yes I can give it a try give me some time or else I will send you the screen code on your mail 

    Thanks again :)

    Supreet


    Supreet
    Friday, May 13, 2011 1:25 PM
  • Hi Yann,

       I am sorry when I try to assign the variables outside wrapper they are only available till I populate them inside the wrapper, after which the code treats them as inaccessible again

    Here is my code if it helps :)

     

    //Wrap BeginInvoke method in Logic Dispather thread
       this.Details.Dispatcher.BeginInvoke(() =>
        {
         #region Populate Grid in Custom Control
    
         //Convert grid to a datagrid
         CustomGrid dgAttendance = (CustomGrid)e.Control;
         DataGrid dg = (DataGrid)dgAttendance.FindName("AttendanceDetails");
    
    
         //Create a custom collection to bind to the grid
         ObservableCollection<StudentAttendanceClass> obsAttendanceAnalysis = new ObservableCollection<StudentAttendanceClass>();
    
         //Get subject id list for all subjects in selected criteria
         IEnumerable<Attendance> attendance = this.DataWorkspace.ApplicationData.Attendances.Where(
          a => a.CollegeId == this.SelectedCollege.Id &&
           a.DepartmentId == this.SelectedDepartment.Id &&
           a.SemesterId == this.SelectedSemester.Id).Execute();
    
         //Get collection of all students in selected criteria
         IEnumerable<Student> students = this.DataWorkspace.ApplicationData.Students.Where(
          s => s.College.Id == this.SelectedCollege.Id &&
           s.Department.Id == this.SelectedDepartment.Id &&
           s.Semester.Id == this.SelectedSemester.Id).Execute();
    
         //List all unique subject IDs
         List<int?> listOfSubjectIDs = attendance.Select(a => a.SubjectId).Distinct().ToList();
    
    
         //For all students available in Attendance records
         foreach (Student student in students)
         {
          //Declare local Variables to hold temp values
    
          //old
          //double overallAttendancePercentage = 0;//
          //double[] percentage;
          //percentage = new double[listOfSubjectIDs.Count];
    
          //new
          StudentAttendanceClass attendanceClass = new StudentAttendanceClass();
          attendanceClass.Stu_EnrollmentNum = student.EnrollmentNo;//1
          attendanceClass.Stu_Name = student.FullName;//2
    
          //for all distinct subjects
          for (int i = 0; i < listOfSubjectIDs.Count; i++)
          {
           //find total number of lectures engaged for current subject
           IEnumerable<Attendance> FilteredAttendance = this.DataWorkspace.ApplicationData.Attendances.Where(a => a.SubjectId == listOfSubjectIDs[0]).Execute();
           attendanceClass.Sub_TotalLecturesEngagedForCurrentSubject = FilteredAttendance.Select(a => a.OverallAttendancePerSubject).Distinct().Count();//6
    
           //also find no of lectures attended by this student
           attendanceClass.Stu_TotalLecturesAttendedInCurrentSubject = 0;
           foreach (Attendance att in this.DataWorkspace.ApplicationData.Attendances.
            Where(a => a.SubjectId == listOfSubjectIDs[i] && a.StudentEnrollmentNumber == student.EnrollmentNo && a.IsPresent == true))
           {
            attendanceClass.Stu_TotalLecturesAttendedInCurrentSubject++;//4
           }
    
           //calculate this student's % in current subject //3
           attendanceClass.Stu_PercentageAttendanceInCurrentSubject = (attendanceClass.Stu_TotalLecturesAttendedInCurrentSubject /
            attendanceClass.Sub_TotalLecturesEngagedForCurrentSubject) * 100;
    
           //current subject name
           attendanceClass.Sub_Name = this.DataWorkspace.ApplicationData.Subjects.Where(sb => sb.Id == listOfSubjectIDs[0]).FirstOrDefault().Name;//5
          }
    
          //Add current details in observable collection
          obsAttendanceAnalysis.Add(attendanceClass);
         }
    
         //Bind the grid with this observable collection
         dg.ItemsSource = obsAttendanceAnalysis;
    
         #endregion
        });
    

     

    Just to update: According to Eric's comment here

    http://social.msdn.microsoft.com/Forums/en/lightswitchgeneral/thread/4806ecaa-88e4-409b-b8e6-b2a674fbae28

    we can call the BeginEnvoke() on main thread as well 

    Dispatchers.Main.BeginInvoke(() =>
    {
    // Write your code here.
    
    });

    Can we somehow use a mix and match of both of these to achieve what I am trying to..

    Thanks & Regards

     


    Supreet
    • Edited by Supreet tare Friday, May 13, 2011 1:37 PM Updated
    Friday, May 13, 2011 1:33 PM
  • Hi Yann,

       Linked original post here.

    Regards

    Supreet


    Supreet
    Friday, May 13, 2011 1:41 PM
  • hello friends,

       I am stuck here, any help is appreciated :)

     

    Regards


    Supreet
    Friday, May 13, 2011 4:32 PM
  • Can you tell us on which line the exception is being thrown? It will help us target the problem.
    Justin Anderson, LightSwitch Development Team
    Friday, May 13, 2011 7:25 PM
  • Hi Justin,

     One more update is, in the code above the entire block is wrapped inside BeginEnvoke this throws error "Invalid cross-thread access." 

     

    at the line where I am trying to find the data grid control i.e. DataGrid dg = (DataGrid)dgAttendance.FindName("AttendanceDetails");

    If I do not use BeginEnvoke I get error "It is not valid to call Execute() on a different Dispatcher than the ExecutableObject's Logic Dispatcher."

     

     

    this occurred at first occurrence of execute i.e. at the time when I am creating  IEnumerable<Attendance> attendance object but if this is becase of Execute method then there are 2 more Occurrences in that code

     

    IEnumerable<Student> students & IEnumerable<Attendance> FilteredAttendance will also throw error going forward.

    let me know if any further info is required 

    Thanks for trying to help :)

     


    Supreet
    • Edited by Supreet tare Friday, May 13, 2011 7:45 PM Edited Grammar
    Friday, May 13, 2011 7:43 PM
  • Looks like you are running this code in a ControlAvailable event handler.

    Your problem is that you are trying to interact with Silverlight UI (objects owned by the main thread) and LightSwitch data (objects owned by a logical thread) interspersed in your code.

    I think you should perform a BeginInvoke immediately on the dispatcher of the screen (like you have in the code that you posted) and perform all of your querying immediately in the beginning of that. Then perform a BeginInvoke on the main dispatcher within the BeginInvoke of the screen's dispatcher into order to get the data grid control reference and set its ItemsSource property.

    If what you are trying to do is perform some kind of transform on your data to display it in some kind of aggregated way, I think a better solution is to refactor your entity schema in a more normalized way that enables this. That way, you wouldn't need to create a custom control and write a lot of code to just display it.


    Justin Anderson, LightSwitch Development Team
    • Marked as answer by Supreet tare Saturday, May 14, 2011 2:27 PM
    Saturday, May 14, 2011 7:42 AM
  • Hi Justin,

         Thanks for responding. I will try with what you have suggested here & will update here on what i find.

    However, I am not doing this to just transform the data but trying to display data in a grid for which the columns are designed at run time.

    My screen will display attendance summary for all students belonging to a college, department, semester

    Here is a quick preview from my existing dot net 2.0 application, that I am currently rewritting with LS

    http://twitpic.com/4xf1ne  (Please choose fullsize from hover options on the pic)

    Now i know I can not access the LS datagrid to modify its columns on the fly that is why I am using a Silverlight grid inside a custom control.

    Kindly suggest me if you have any better ideas to accomplish this. 

    Meanwhile I am gonna try with your current suggestion, lets see if I am able work it out.

    Thanks & Regards

     

     

     


    Supreet
    Saturday, May 14, 2011 9:16 AM
  • Hi Justin, 

        I tried your suggestion and wrote this block of code 

    Dispatchers.Main.BeginInlineInvoke(() =>
              {
                //Convert grid to a datagrid
                CustomGrid dgAttendance = (CustomGrid)e.Control;
                DataGrid dg = (DataGrid)dgAttendance.FindName("AttendanceDetails");
    
                //Bind the grid with this observable collection
                dg.ItemsSource = obsAttendanceAnalysis;
              });
    
    inside my screen dispatcher as shown below, this throws a new error "It is not valid to begin an inline invoke on a Dispatcher that is not actively invoking the Current Dispatcher." Please shad some light on this Thanks 
     this.Details.Dispatcher.BeginInvoke(() =>
          {
            #region Populate Grid in Custom Control
    
            //Create a custom collection to bind to the grid
            ObservableCollection<StudentAttendanceClass> obsAttendanceAnalysis = new ObservableCollection<StudentAttendanceClass>();
    
            //Get subject id list for all subjects in selected criteria
            IEnumerable<Attendance> attendance = this.DataWorkspace.ApplicationData.Attendances.Where(
              a => a.CollegeId == this.SelectedCollege.Id &&
                a.DepartmentId == this.SelectedDepartment.Id &&
                a.SemesterId == this.SelectedSemester.Id).Execute();
    
            //Get collection of all students in selected criteria
            IEnumerable<Student> students = this.DataWorkspace.ApplicationData.Students.Where(
              s => s.College.Id == this.SelectedCollege.Id &&
                s.Department.Id == this.SelectedDepartment.Id &&
                s.Semester.Id == this.SelectedSemester.Id).Execute();
    
    //Rest of the Lightswitch screen related code goes here
    
    
    //THIS IS WHERE I AM CALLING MAIN THREAD
    });
    


    Supreet
    Saturday, May 14, 2011 10:00 AM
  • You should be calling BeginInvoke instead of BeginInlineInvoke.
    Justin Anderson, LightSwitch Development Team
    • Marked as answer by Supreet tare Saturday, May 14, 2011 2:27 PM
    Saturday, May 14, 2011 10:52 AM
  • Oops!! This was completely overlooked by me, the intellisense poped this out first & i completely messed here, I am sorry for that.

    My laptop's battery has died & i forgot to get the charger with me today :(

    I will try this when I reach home.

    Will update you on latest findings

    Thanks for pointing out the error

    Regards

     

     


    Supreet
    Saturday, May 14, 2011 1:27 PM
  • Hi Justin,

       Thanks it worked like a charm, the only thing I am left with is that even after creating an observable collection (which has 6 records in it ) & binding it with the grid I am not able to see the control on the UI.

    Is it possible to 

    1. Create a custom Control having a silverlight grid

    2. Find that SL grid in code & bind it to the collection

    It should work?

    Please point me to any correct implementations you may be aware of.

    Thanks & Regards

    Supreet


    UPDATE: AutoGenerateColumns="true" solved this problem, I can see my grid on the screen now..
    • Edited by Supreet tare Sunday, May 15, 2011 5:37 AM Updated with Answer found
    • Marked as answer by Supreet tare Sunday, May 15, 2011 5:37 AM
    Saturday, May 14, 2011 2:30 PM
  • Hi Supreet, I kind of meant the other way around, lol. So I meant put a link in THIS post that takes people to the *original* post if the want to see what the original problem was. :-) Yann
    Saturday, May 14, 2011 11:10 PM
  • Its Done and working as expected 

    Thanks Justin, Yann & all for your support. 

    This was the first chance i encountered a problem with threading in LS & solving it with help from you guys led me to read quit a lot about it.

    Not only this problem is solved I've also learned some fantastic concepts when working on this.

    Thanks Again 

    Regards


    Supreet
    Sunday, May 15, 2011 5:35 AM