locked
How to listen the elements load data comepleted ? RRS feed

  • Question

  • As the title said, when i specify the List object to some element's ItemsSource (like FilpView, GridView, ListItemView etc) property, how to I can know that the element bind the list to UI completed.  

    I can't find the related event. 

    Thursday, August 23, 2012 3:52 AM

Answers

  • Hi,

    use the ItemContainerGenerator.ContainerFromIndex method to get the current itemcontainer, then subscribe to last ones Loaded event. Or there's the GetContainerForItemOverride method if you create an extension to the original GridView/FlipView, etc.

    Hope this helps,

    Cssabee

    • Marked as answer by Gabb_CHN Friday, August 24, 2012 2:46 AM
    Thursday, August 23, 2012 8:21 AM

All replies

  • i dont think there is event for that. why you need it?
    Thursday, August 23, 2012 6:21 AM
  • Hi,

    use the ItemContainerGenerator.ContainerFromIndex method to get the current itemcontainer, then subscribe to last ones Loaded event. Or there's the GetContainerForItemOverride method if you create an extension to the original GridView/FlipView, etc.

    Hope this helps,

    Cssabee

    • Marked as answer by Gabb_CHN Friday, August 24, 2012 2:46 AM
    Thursday, August 23, 2012 8:21 AM
  • Isn't this layoutupdated event? basically when there is a change in the data context, the item has to redraw itself... even if there is no change in the visual tree, the event would still fire denoting that there was some update completed. And again as the documentation suggests LayoutUpdated is the last object lifetime event to occur in the XAML load sequence before a control is ready for interaction.

    Here you can take a look: FrameworkElement.LayoutUpdated.


    Can Bilgin
    Blog CompuSight

    Thursday, August 23, 2012 2:59 PM
  • Hi Can,

    Yes but [unfortunately] ...

    - LayoutUpdapted has a nasty tendency to provide you with null sender and null object values; that can be alleviated by writing a (lot of) subclasses when sealed does not get in the way :-) -> hence minor roadblock
     - In my understanding, a detection in DataContext change (if it had been available) serves in practice to modify the layout like a smallish [local and instance based] datatemplateselector. The fact that you'd update [even partially] the VisualTree _after_ getting the LayoutUpdate event defeats of course that very purpose [of using the DC change] since you force a reevaluation of the tree. -> major roadblock
    ---
    In a nutshell, I would _never_ use LayoutUpdated because of above aspects ... but I might be too pessimistic or plain wrong of course. What do you think?


    • Edited by ForInfo Thursday, August 23, 2012 3:15 PM
    Thursday, August 23, 2012 3:15 PM
  • Cssabee's suggestions provide a partial solution. I have documented the findings in the following snippet:

    public sealed partial class MyListView : ListView
        {
            public MyListView()
            {
                ItemContainerGenerator.ItemsChanged += OnItemsChanged;
            }
    
            private void OnItemsChanged(object sender, ItemsChangedEventArgs e)
            {
                // Exec
                Debug.WriteLine("OnItemsChanged:{0}", e.Action);
            }
    
            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
            {
                // Exec
                base.PrepareContainerForItemOverride(element, item);
    
                // At this stage,
                // - Element.DataContext is always set to the expected value, i.e. usually 'item'
                // - However, the FrameworkElements in the ListViewItem.ItemTemplate are not guaranteed to have been created;
                //   - if elem.Applytemplate() is invoked here[*] on a 'virgin' ListViewItem, 
                //     that operation will set the expected DataContext in the templated elements
                //   - however, the same operation on a 'recycled' ListViewItem, leaves the 'old' DataContext at this stage of the processing
                //
                //
                // [*] implying a performance penalty
            }
        }



    • Edited by ForInfo Thursday, August 23, 2012 4:04 PM
    Thursday, August 23, 2012 3:23 PM
  • You make good points and I agree that layoutupdated should be handled with care  but did you read the question? :) he just want to know when exactly he can be sure that binding is complete, I wouldn't go as far to update the context when the binding is done, and why would I since data is bound layout is drawn.

    Can Bilgin
    Blog CompuSight

    Thursday, August 23, 2012 4:00 PM
  • Your conclusion is correct: I 'extended' the question by wrongly assuming that changing UI layout [in some form or another] was the 'hidden' purpose. If it is just to be 'informed' then there is indeed no harm to listen for that 'ultimate' event. Thanks for pointing that out! 

    Thursday, August 23, 2012 4:09 PM
  • To Can & ForInfo, 

    LayoutUpdated can solve my problem.  Thanks for all of your advice.

    According the MSDN, ItemContainerGenerator.ItemsChanged is triggered when the collection is modify.

    LayoutUpdated can listened the last element binding. If I need to get the notify when each element binding complete, how can i do ? (Just like the Gridview.RowDataBound event in ASP.NET)

    Friday, August 24, 2012 2:46 AM
  • My summary is:

    1.- In case of a event-driven approach:

    - There is no bind-element complete event [Dave] 
    - The only event that guarantees a bound state is the LayoutUpdated event [Can]
    - There are several techniques to listen for the LayoutUpdated event [CssaBee]. There are limitations [ForInfo] as well as 'false positive' signals [msdn documentation see 'Remarks, second paragraph' in particular]
    - It is a suboptimal design decision to modify anything in the visual tree further to being notified by LayoutUpdated. If this is the intention, other techniques should be resorted to. [ForInfo]

    2.- In case of a method override approach:

    - One can design a UserControl as a DataTemplate for a ListViewItem
    - One can override its method MeasureOverride(...) by (1) calling base.MeasureOverride(...) and (2) use this location to exploit 'binding done state' [since otherwise measurement could not occur]. One could (e.g.) dispatch some deferred execution at this point.
    - Again, this is more of a 'hacking' technique than anything else but it has the advantage of sending less 'false positive' signals. In case a ListView uses a Virtualizing panel, the 'measurement' evaluation will be correctly restricted to 'active' ListViewItems. In case of an ItemsControl, this is unfortunately not the case: all ObservableCollection<...> items are measured upfront even with a Virtualizing panel. 

    ---

    Back to your last questions:

    "If I need to get the notify when each element binding complete, how can i do" : use the techniques proposed by [CssaBee] _or_ data template your ListViewItem as a 'big' UserControl, within which (1) you place [e.g. in the Constructor] a this.LayoutUpdate += HandlerToProcessOnEvent or (2) use the MeasureOverride(...) technique.

    "LayoutUpdated can listened the last element binding.": if you need some form of aggregated information, place the this.layoutUpdate += HandlerToProcessOnEvent in a class that extends the ListView.


    • Proposed as answer by Can Bilgin Friday, August 24, 2012 10:48 AM
    • Edited by ForInfo Friday, August 24, 2012 12:40 PM
    Friday, August 24, 2012 5:49 AM