locked
How to get a specific visual element from Gridview Selection Changed event - not the data?

    Question

  • What do I want to do?
    Select an item in a gridview, raise the appbar, hit a favorite button there and then update the selected gridviewitem with a visible Favorite-Symbol wich was collapsed by default in my datatemplate.

    My Problem
    My Problem is, that I need to set the visibility of the specific element inside my gridview wich is inside my datatemplate.
    I can get the selectedItem without any problem...

    private void GridSelectionChanged(object sender, SelectionChangedEventArgs e)
     {
            GridView gridView = sender as GridView;
    	var item = gridView.SelectedItem;
     }

    But "tem" would not be the type GridViewItem but the datamodel itself. I tried with every possible method and combination from UIHelper until I realised that there is no info about visual elements at all inside "SelectedItem". I thought mabye something of ContentPresenter but couldn't figure out how. Or something with selectedIndex maybe?

    How would I access my Textblock, containing the heart-symbol, named "favIcon" ?

    My XAML for the Datatemplate looks like this (I stripped it down a bit):

    <DataTemplate x:Key="MyItemTemplate">
                <Grid x:Name="MyItemGrid" Width="200" Height="260" Margin="5">
                    <Canvas Background="#FFDDDDDD"/>
                    <Canvas Background="White" Height="230" VerticalAlignment="Top" Margin="2,2,2,0"/>                
                    <TextBlock x:Uid="favIcon" x:Name="favIcon" Text="&#xE0A5;" Visibility="{Binding FavIconVisibility}" Foreground="#FF14408D" FontFamily="Segoe UI Symbol" FontSize="18" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,3" />                
                </Grid>
            </DataTemplate>

    Friday, February 21, 2014 3:39 PM

Answers

  • Yes, you're probably right that it is firing before the binding is complete. Like I said, this is not an elegant solution. You may want to listen for the loaded event on an item which will be loaded after the textblock is binded so that you can get information not only for the textblock, but for other items in the parent's container.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    • Marked as answer by SW_Andy Friday, February 28, 2014 10:57 PM
    Thursday, February 27, 2014 1:36 PM
    Moderator

All replies

  • There are a couple of ways. I usually use the loaded event, but my buddy Jerry Nixon has another technique:

    http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Friday, February 21, 2014 4:38 PM
    Moderator
  • Hi Matt, thanks for the fast reply. 

    But I found that article before and tried that approach too, but it's failing for me - maybe I'm doing something wrong? But I followed the example to the letter... only difference is that I need to look inside a gridview not listbox and I have also to look inside a Grid in the gridViewItem.

    When I simply try that:

    foreach (var gvItem in myGridview.Items)
                {
                    Debug.WriteLine("gvItem: " + gvItem);
                    var Container = myGridview.ItemContainerGenerator.ContainerFromItem(gvItem);
                    var Children = AllChildren(Container);
                    //var name = "favIcon";
                    //var control = (TextBox)Children.First(c => c.Name == name);
                }

    It fails in the line with the ItemContainerGenerator.ContainerFromItem with a System.NullReferenceException.
    But  the Debug line before returns my DataModel again.


    EDIT:
    And maybe I should mention that I look in a generated Gridview inside a Hubsection


    • Edited by SW_Andy Saturday, February 22, 2014 1:29 PM
    Saturday, February 22, 2014 12:58 PM
  • Well... I'm not giving up on that ;)

    In the example on a newly created HubPage Template from VS2013,
    it also simply fails with a NullReference. It's either bugged or outdated with Windows 8.1?

    VS2013 is also complaining, that "ItemContainerGenerator.ContainerFromItem" is obsolete and you should use "ItemsControl.ItemFromContainer".

    Also I can't find anywhere a concrete example how to use ItemsControl.ItemFromContainer - and I found several threads on stackOverflow and here that people don't know how to use it.

    myGridView.ItemsControl.ItemFromContainer fails with "GridView does not contain a definition of ItemsControl" wich is funny, since it suggested it in the obsolete warning.



    • Edited by SW_Andy Monday, February 24, 2014 9:31 AM
    Monday, February 24, 2014 9:23 AM
  • I prefer the dictionary approach - it's not elegant BUT it works for me every time.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Monday, February 24, 2014 2:09 PM
    Moderator
  • Hi Matt,

    I'm still totally stuck here. Could you please explaine what you mean with the dictionary approach? I really wanted to go down the VisualTree-Road. But if everything else fails I'm open for any unelegant practice ;)

    Still also I'm curious why it's returning a NullReference and how to use ItemGenerator at all... seen none working example or sample code for that case (especially since VS2013 is telling me that ItemContainerGenerator is obsolete).#

    Thanks,Andy

    Tuesday, February 25, 2014 8:41 AM
  • Subscribe to the "loaded" event for the TextBlock inside the datatemplate.  Every time the GridView binds to another item, that TextBlock will fire the loaded event.  In the handler for the loaded event, store the a reference to that TextBlock into a list, and some way to uniquely identify that particular TextBlock.  All of the TextBlocks will end up inside the list.

    When the GridView selection changes, handle that event, and use the data that was selected to map it back to one of the TextBlocks in the list of TextBlocks.

    It may be that using the TextBlock alone won't work.  You may have to subscribe to the loaded event on a parent control - such as the Grid  - and have some other hidden value inside the DataTemplate that allows you to determine which TextBlock was chosen.


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Wednesday, February 26, 2014 1:39 PM
    Moderator
  • Thanks, that sound like a good way to do it. Just tried it out... and it worked - well partly. I bound the tag of the textblock to an unique identifier. I'm also getting the textblocks. But it seems that the loaded event fires before the binding is complete - can that be?

    Because I always get the first item correctly, but only that. All consecutively were empty.

    I made a function to reset/repopulate the data for the observable collection and after I execute that function, every loaded event gets it's textblocks and tags correctly. Same behaviour on the parenting grid also.



    Thursday, February 27, 2014 11:53 AM
  • Yes, you're probably right that it is firing before the binding is complete. Like I said, this is not an elegant solution. You may want to listen for the loaded event on an item which will be loaded after the textblock is binded so that you can get information not only for the textblock, but for other items in the parent's container.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    • Marked as answer by SW_Andy Friday, February 28, 2014 10:57 PM
    Thursday, February 27, 2014 1:36 PM
    Moderator
  • Thanks Matt... I think that's as close to an answer as I can get. That's a good hint and I'll try further.
    • Edited by SW_Andy Friday, February 28, 2014 10:59 PM
    Friday, February 28, 2014 10:58 PM