Sugz
Sugz

Reputation: 107

WPF Get the associated ListView in a GridView

I'm trying to implement a custom GridView for the ListView, but I need to find a way to get the ListView that is associated with the GridView, since I need to access some of the ListView properties (Width, Items, Template...).

I found an old post that was asking the same question Get the parent listview from a gridview object but it never got an answer...

If anyone has an idea, I would be glad :)

EDIT: Here some basic code from the custom GridView

public class GridViewEx : GridView
{
    public ListView Owner {get; set;}     // This is what I need to get

    public GridViewEx()
    {

    }

}

EDIT2: I found another solution than the one presented by mm8. Since I also needed a custom GridViewHeaderRowPresenter, which is used in the ListView Scrollviewer Style, here is what I came up with (as for now):

public class GridViewHeaderRowPresenterEx : GridViewHeaderRowPresenter
{
    private GridViewEx _GridView;

    public GridViewHeaderRowPresenterEx()
    {
        Loaded += OnLoaded;
        Unloaded += OnUnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        if (this.GetVisualParent<ListView>() is ListView lv && lv.View is GridViewEx gridView)
        {
            _GridView = gridView;
            _GridView.Owner = lv;
        }
    }

    private void OnUnLoaded(object sender, RoutedEventArgs e)
    {
        if (_GridView != null)
            _GridView.Owner = null;
    }
}

And here is the extension method to get the ListView from the custom GridViewHeaderRowPresenter:

public static class DependencyObjectExtensions
{
    public static T GetVisualParent<T>(this DependencyObject depObj) where T : DependencyObject
    {
        if (VisualTreeHelper.GetParent(depObj) is DependencyObject parent)
        {
            var result = (parent as T) ?? GetVisualParent<T>(parent);
            if (result != null)
                return result;
        }

        return null;
    }
}

The GridViewHeaderRowPresenter Loaded event is called when a GridView is added to a ListView, and the Unloaded event is called when the GridView is removed from the ListView.

I prefer this solution over the one from mm8, since it required (if I'm not mistaken) the ListView to have Items in order to work.

Thanks for the suggestions :)

Upvotes: 2

Views: 767

Answers (2)

mm8
mm8

Reputation: 169300

You could override the PrepareItem method and use the ItemsControl.ItemsControlFromItemContainer method to get a reference to the parent ListView:

public class GridViewEx : GridView
{
    public ListView Owner { get; set; }

    public GridViewEx()
    {

    }

    protected override void PrepareItem(ListViewItem item)
    {
        base.PrepareItem(item);
        Owner = Owner ?? ItemsControl.ItemsControlFromItemContainer(item) as ListView;
    }
}

Upvotes: 2

Liuk
Liuk

Reputation: 111

You can use Binding with RelativeSource and AncestorType, try the code below:

XAML:

<Grid>
    <ListView ItemsSource="{Binding}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
                <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
                <GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
                <GridViewColumn Header="Test">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Button
                                DataContext="{Binding Path=ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}"
                                Content="Get ListView ItemsSource Count"
                                Click="Test_Click" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>

C#:

class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Mail { get; set; }
}

public MainWindow()
{
    InitializeComponent();
    DataContext = new List<User>
    {
        new User() { Name = "John Doe", Age = 42, Mail = "[email protected]" },
        new User() { Name = "Jane Doe", Age = 39, Mail = "[email protected]" },
        new User() { Name = "Sammy Doe", Age = 7, Mail = "[email protected]" }
    };
}

private void Test_Click(object sender, RoutedEventArgs e)
{
    if (sender is FrameworkElement fe)
        if (fe.DataContext is List<User> users)
            MessageBox.Show($"ItemsSource items count: {users.Count()}.", "ListView Test");
}

Upvotes: 0

Related Questions