Search code examples
c++-winrtwinui-3

How to get the parent of an object in WinUI3 with C++/WinRT?


This is how the xaml looks like:

<ListView HorizontalContentAlignment="Stretch"
                      x:Name="listViewMessages"
                      Grid.Column="1"
                      ItemsSource="{x:Bind MessageViewModel.Messages}"
                      Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualHeight}"
                      ItemClick="listViewMessages_ItemClick">
                <ListView.HeaderTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                ...
                            </Grid.ColumnDefinitions>
                        </Grid>
                    </DataTemplate>
                </ListView.HeaderTemplate>

                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:Message">
                        <Grid HorizontalAlignment="{x:Bind Path=MineToHorizontalAlignment()}" Background="{x:Bind Path=MineBackgroundColor()}" CornerRadius="8" Margin="0,6,0,2" Padding="6">
                            <Grid.ColumnDefinitions>
                                ...
                            </Grid.ColumnDefinitions>

                            ...
                            <Button Grid.Column="5" Click="Button_Click">D</Button>
                        </Grid>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

So when I will click the button I want to get the list view item of the clicked button.

How can I achieve this?

Edit: I changed the xaml example to a more specific one.


Solution

  • You need to use the VisualTreeHelper Class to traverse the visual tree. Here is a C++/WinRT utility to walk the parents recursively:

    template <typename T>
    T GetParent(DependencyObject obj)
    {
        if (!obj)
            return nullptr;
    
        auto parent = Microsoft::UI::Xaml::Media::VisualTreeHelper::GetParent(obj);
        if (!parent)
            return nullptr;
    
        auto parentAs = parent.try_as<T>();
        if (parentAs)
            return parentAs;
    
        return GetParent<T>(parent);
    }
    

    And it's C# counterpart for what it's worth:

    public static T GetParent<T>(DependencyObject obj) => (T)GetParent(obj, typeof(T));
    public static object GetParent(DependencyObject obj, Type type)
    {
        if (obj == null)
            return null;
    
        var parent = VisualTreeHelper.GetParent(obj);
        if (parent == null)
            return null;
    
        if (type.IsAssignableFrom(parent.GetType()))
            return parent;
    
        return GetParent(parent, type);
    }
    

    So you would call it like this:

    void MainWindow::Button_Click(IInspectable const& sender, RoutedEventArgs const&)
    {
        auto listView = GetParent<Controls::ListView>(sender.try_as<DependencyObject>());
    }