locked
UserControl event order? RRS feed

  • Question

  • We have a UserControl that contains a DataGrid.  Each DataGrid row contains a CheckBox.  I would like to know when the entire control has completed loading and rendering.  However, the order of events has me quite confused, and wondering which event I can use for this.  For example, the UserControl's Loaded event fires before the DataGrid's, which is counterintuitive to me and seems to contradict the documentation.  Also, the DataGrid's Loaded event fires before the CheckBox's.  This makes it very difficult to figure out when the UserControl has, in fact, completed loading!  It seems as though the closest I can get is to tie into the last time the CheckBox's Loaded event fires.  Needless to say, that is a pain and seems very much like the wrong way to do it.

    Any ideas?

    Thanks!

    Brad.

    Thursday, June 9, 2011 3:24 PM

All replies

  • Do you have some xaml code to show the logic?
    Thursday, June 9, 2011 5:08 PM
  • Welcome to the wonderful but magical world of events.  You have already researched this enough to have determined that what you may have thought was the case wasn't.  Part of this is due to knowing what the real meaning of the events are.  I know for example that I can create a user control that contains a datagrid of which I can bind the datagrid to an asynchronous web service.  I also know that the user control will fire loaded event before datagrid is loaded.  So the real issue is to dechiper what the word Load means within the context of a user control and all of its children.

    If you know that a control is going to be loaded late, either through Asynchronous or dynamic binding at run time, then you should key off that control to know when everything is ready.  For example when using WCF or RIA for loading data into a grid, the paradigm taught is to fire off the load request and to catch it in the loaded event handler for filtering purposes.  This is how they teach it when studying RIA or WCF.  In this particular case the user control load has nothing to do with the Datacontext load.  You can load any user control without datacontext at any time.  You just won't see any data.  I think the real issue you are facing is with this question "When does the datacontext and bindings finish?"  The answer is...it depends on how you've done it.

    I try to always use Datacontext loads within the view via a static resource in the usercontrol's resources section of that user control.  I then will specify the datacontext to be bound to the closest parent control.  For example in your case I'll set datacontext in the Datagrid, and then use a path statement to the checkbox binding for IsChecked.  I think I can always be assured that when the Datagrid loaded event fires, I'll have all the data with one exception.... loading the data is not the same as rendering the data.  It takes time for the runtime to render big datacontext...  So if you are fighting with that, then the only option you have is to reduce the size of data being displayed.  I call this Paging.... There are lots of techniques for paging out there so you may need to look into that..  WCF and RIA have paging built into their methodology...

     

    Hope this helps.


    JP
    Thursday, June 9, 2011 5:08 PM
  • The XAML would look something like:
    <UserControl ...>
     <Grid ...>
      <DataGrid ...>
       <DataGrid.Colums ...>
        <DataGridTemplateColumn>
         <DataGridTemplateColumn.CellTemplate>
          <DataTemplate>
           <CheckBox IsChecked="{Binding IsSelected}" Loaded="SelectedColumnCheckBox_Loaded" Click="SelectedColumnCheckBox_Click" />
          </DataTemplate>
         </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn >
       </DataGrid.Colums>
      </DataGrid>
     </Grid>
    </UserControl>
    
    
    Thanks!
    Brad.
    Thursday, June 9, 2011 7:26 PM
  • Unfortunately, whereas what you're saying makes sense, it gets me no closer to my goal.  How can I tell when the runtime has completed rendering the data?  Ultimately, that's what I'm interested in.  I understand what you're saying about the asynchronous possibilities, but I would think there should be some kind of event that says "The asynchronous event I was waiting for has completed, and I'm all done getting the data, binding the data, rendering, painting, and whatever else needs to happen".  Yes, there might be a disconnect between the "Loaded" event and the kind of event I describe, but....  For example, if I'm waiting for the result of an asynchronous call, I will have an event to indicate that it has completed.  Is there not a similar one to say the control has completed the redraw that occurred because the data in the DataContext changed?

    Thanks!

    Brad.

    Thursday, June 9, 2011 7:32 PM
  • I have not found a way to differentiate from loaded and render complete.  You could try to catch the onRender event, but that's just the start and not the end...  As far as I know there is no way to determine render complete.  And we pointed out earlier there is a difference between datacontext loaded and control loaded as well.  As mentioned eariler if you are loading a ton of data, you need to page it in rather than glom it all in at once.  That's the best way to see things ASAP...
    JP
    Thursday, June 9, 2011 9:16 PM
  • Hi Brad,

    It is documented that the Loaded events fires from top to bottom. The following is quoted from the documentation:

    "the Loaded event is raised as a coordinated effort throughout the entire element tree (specifically, the logical tree). When all elements in the tree are in a state where they are considered loaded, the Loaded event is first raised on the root element. The Loaded event is then raised successively on each child element."

    Also, when the UserControl's Loaded event fires, the LogicalTree that contains the UserControl is completed and all elements in that tree has already been loaded. i.e. At the time UserControl fires the Loaded event, the DataGrid IsLoaded.

    Generally, I think you can just use the UserControl's Loaded event. You didn't mention what you want to accomplish when the event fire. In case the UserControl's Loaded event cannot work, please kindly elaborate your question so that we can provide further assistance.

    Have a nice day!

    Best regards,

     

     


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, June 10, 2011 3:45 AM
  • In our case we are having some serious performance issues that we're trying to track down.  We're not so much needing to do something specific at the point that rendering is complete as we are trying to understand what's going on in our app, and why rendering is taking so long.  Knowing when a given control has finished rendering would give us a much better understanding of where the bottlenecks are and what we can do to fix them.  For example, we have an action which loads a user control.  The "Loaded" event is raised within about two seconds, but the application remains unresponsive for at least another five seconds after that.  Given that we are dealing with a relatively small data set (in the neighborhood of 100 rows), this seems excessive, but we're having some difficulty, even with profilers, figuring out what the problem is.

    Brad.

    Monday, June 13, 2011 3:40 PM
  • P.S.  We'd also like to tie into some kind of "render complete" event so as to close our splash screen at a more appropriate time.  :-)

    Brad.

    Monday, June 13, 2011 3:54 PM
  • Hi Brad,

    In that case, I suggest you to use the Visual Profiler in WPF Performance Suite.

    "Visual Profiler is a performance profiling tool of WPF services, such as layout, rendering, and animation, for elements in the visual tree. By analyzing the profiling output of this tool, you can determine which visual elements in your application may be causing performance bottlenecks."

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, June 14, 2011 5:32 AM
  • I think I would consider gotfocus for your splash screen issue.

     

    Tuesday, June 14, 2011 10:44 AM
  • Actually, we've been trying to use the profiler, but for reasons we haven't figured out yet, it's not working properly with our application.  That's an entirely separate avenue of investigation!

    I take it you'e telling me the event I want doesn't actually exist?

    Brad.

    Tuesday, June 14, 2011 10:28 PM
  • I don't know how "got focus" would help with the splash screen issue.  Can you elaborate?

    Thanks!

    Brad.

    Tuesday, June 14, 2011 10:29 PM
  • Hi Brad,

    As far as I know, there isn't such a event that fires on render completed.

    Do you have any custom code running after the Loaded event fires?

    Please try this link to download the WPF Performance Suite and its patch.

    For WPF performance issues, please also check out this page if you haven't done so.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, June 15, 2011 3:33 AM
  • I don't know how "got focus" would help with the splash screen issue.  Can you elaborate?

    Thanks!

    Brad.


    I'm assuming you put a splash screen up and then show something else.

    Screen X.

    Once Screen X has been rendered to the screen it will eventually fire a gotfocus event.

    At that time your splashing is done and the user can get on and do his thing with screen X so you can unload X.

    Wednesday, June 15, 2011 11:10 AM
  • Actually, the splash screen was a red herring - I shouldn't have mentioned it.  It's working correctly.  Coincidentally, the splash screen is pretty much exactly the kind of behavior we'd like to capture.  It disappears properly when the main window is done rendering and is available for user interaction.  This is some time after the "loaded" event, in our case.

    Brad.

    Wednesday, June 15, 2011 4:46 PM
  • No, we don't have custom code running after the "Loaded" event.  However, here's another scenario.  We have some controls that render VERY slowly.  We're trying to figure out how to improve their performance, but if we can't, we'd like to put up an indeterminate progress bar or something so that the user knows something is happening and the application hasn't crashed.  However, we would need some kind of event to tie into to hide the progress bar.

    Obviously our first priority is, as you say, improving the performance of those controls.  However, if that's not possible, we have to find alternatives.

    Thanks!

    Brad.

    Wednesday, June 15, 2011 4:51 PM
  • It's also possible that I'm chasing down the wrong path entirely!  I've been saying the problem is rendering, but maybe the problem is the data binding process.  All I know is that I'm trying to display a control with only about 135 rows in it and it's taking in excess of five seconds on a fast machine to complete and become responsive again.  That seems ridiculously long to me!

    Brad.

    Wednesday, June 15, 2011 5:05 PM
  • Have you checked how long it takes to get the data?

    Wednesday, June 15, 2011 5:43 PM
  • The data is all there before any of this happens.  It is 100% loaded and in memory.  There is no deferred execution or anything else going on.

    I'm going to see if I can put together a "sterile" example that I can share.

    Thanks!

    Brad.

    Wednesday, June 15, 2011 5:47 PM
  • Brad;

    I've already indicated that WPF takes time to render GUI content, this after the load event (from my past experinence).  You have to reduce the amount you are displaying to speed things up.  This is why data paging and ADO.NET concepts such as paging in data have come to light recently.


    JP
    Wednesday, June 15, 2011 7:19 PM
  • Hi Brad,

    Any update on this issue?


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, June 20, 2011 2:26 AM
  • OK, here's the latest.  Whereas I still lament the fact that there doesn't seem to be an event for "render complete", in our case we no longer need it as badly.

    What I could never understand was why, despite using controls that supported "VirtualizingStackPanel" (DataGrid or TreeView), setting "VirtualizingStackPanel.IsVirtualizing" never made a difference.  I eventually took the time to simplify it to some basics, and that's when I learned that the "Accordion" from the "WPF Toolkit" (http://wpf.codeplex.com/) doesn't support it.  Not only does it not support it, it negates it (i.e. the entire control must render).

    I hope that helps someone else with similar isses!

    Brad.

    P.S.  I don't feel like I can mark this question "answered", since whereas the issue may not be active, I'd still like to hear about an event that might work as a "render complete", especially for controls that support "VirtualizingStackPanel".

    • Edited by Pletzky Monday, June 20, 2011 2:56 PM Additional info
    Monday, June 20, 2011 2:53 PM
  • From VirtualizingStackPanel doc:

    The standard layout system creates item containers and computes layout for each item associated with a list control. The word "virtualize" refers to a technique by which a subset of user interface (UI) elements are generated from a larger number of data items based on which items are visible on-screen. Generating many UI elements when only a few elements might be on the screen can adversely affect the performance of your application. The VirtualizingStackPanel calculates the number of visible items and works with the ItemContainerGenerator from an ItemsControl (such as ListBox or ListView) to create UI elements only for visible items.

    Words of importance to me are "a subset...are generated...based on which items are VISIBLE on screen"  Generating many UI elements when only a few are on screen can adversely affect the performance.

    So as mentioned before, you have to be cognizant of how much data is being bound, but also how much of it is visible.  Without the virtualization there is an attempt to render all regardless of visibility.  In Silverlight they have paging support built-in, but I'm not sure about WPF...  Here's a few links http://www.google.com/search?source=ig&hl=en&rlz=1R2ADRA_enUS397&q=wpf+paging&aq=f&aqi=g6g-v4&aql=&oq=

    What is paging anyway?  It is just the ability to know how many records to retrieve in order to display.  This same technique can be easily implement using LINQ.  Like this:

    from o in dx.Orders         
    where o.CustomerID == somevalue
    select o.Take(5); 
    


    You can see from the LINQ statement above you have full control in just one parm. on what you want to display.

    So the design would be 1) Do the query asynchronously.  2) Bind to the LINQ result callback and only take what records you need.

     

     


    JP
    Monday, June 20, 2011 5:00 PM
  • Hi Pletzky,

    Although this documentation says the the Loaded event fires before the final rendering. Based on my experience Loaded event can be regarded as render complete. I am not sure why it is behaviors differently in your case, but you can always use Dispatcher.BeginInvoke method to get into any priority level you want.

    Also, in WPF, the final rendering is fully managed by WPF not by the application itself. So a RenderCompleted event doesn't make much sense for a control. For the applicaton, CompositionTarget.Render event will fire right before rendering, or you can say it will fire after the previous frame is rendered.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, June 21, 2011 9:33 AM