locked
Hiding ListViewItem on binding

    Question

  • I'm trying to hide specific ListViewItems based on a property in the datacontext.

    I currently have a property

        bool show;

    which is implementing INotifyPropertyChanged. I'm using a converter to convert this to a visibility.

    I'm currently using the visible property on the ContentPresenter in the ListViewItemContainerStyle.

    The content of the ListViewItem is hidden correctly, however a blank space is still shown where the ListViewItem would of been.

    What is the correct way to hide the ListViewItem completely (but still have the item in the ListView's datasource).

    Monday, October 20, 2014 8:20 PM

Answers

  • You could always handle the Loaded event for the root element in your ItemTemplate and use a visual tree helper to find the ListBoxItem. Please refer to the following example which hides the first item in the ListView, i.e. the container for the MyItem object with its Hide property set to true:

    public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
    
                lv.ItemsSource = new List<MyItem> { new MyItem { Name = "1", Hide = true }, new MyItem { Name = "2" } };
            }
    
            private void StackPanel_Loaded(object sender, RoutedEventArgs e)
            {
                StackPanel sp = sender as StackPanel;
                if (sp != null)
                {
                    ListViewItem lvi = FindParent<ListViewItem>(sp);
                    if (lvi != null)
                    {
                        MyItem dataObject = sp.DataContext as MyItem;
                        if (dataObject != null)
                            lvi.Visibility = dataObject.Hide ? Visibility.Collapsed : Visibility.Visible;
                    }
                }
            }
    
            private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
            {
                var parent = VisualTreeHelper.GetParent(dependencyObject);
    
                if (parent == null) return null;
    
                var parentT = parent as T;
                return parentT ?? FindParent<T>(parent);
            }
    }
    

    <ListView x:Name="lv">
                <ListView.Resources>
                    <local:MyConverter x:Key="conv"/>
                </ListView.Resources>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Loaded="StackPanel_Loaded">
                        <TextBlock Text="{Binding}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
    
    Please remember to mark helpful posts as answer and/or helpful.
    Wednesday, October 22, 2014 8:34 PM

All replies

  • What value do you set the Visibility property of the ListViewItem to in your converter? You should set it to Collapsed rather than Hidden to completely remove the space reserved for it from the visual tree.

    Also make sure that you are setting the Visibility property of the ListViewItem itself to Collapsed:´

    <ListView>
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="Visibility" Value="{Binding YourSourceProperty, Converter={StaticResource yourConverter}}"/>
                    </Style>
                </ListView.ItemContainerStyle>
            </ListView>

    Please remember to mark helpful posts as answer and/or helpful.

    Monday, October 20, 2014 9:21 PM
  • I'm setting the property to collapsed in the converter but still having this issue.

    If I set the visibility property on the actual ListViewItem there is no effect at all. I'm assuming the binding is not available that far up the visual hierarchy (seems to stop having any effect on the parent container of the ContentPresenter).

    How else can I achieve this?

    Thanks

    Tuesday, October 21, 2014 8:08 AM
  • You are right. It appears that bindings are not supported on Setters. Please refer to the following page for more information and a possible workaround using an attached dependency property: http://stackoverflow.com/questions/11857505/how-do-i-do-bindings-in-itemcontainerstyle-in-winrt
    Tuesday, October 21, 2014 9:15 PM
  • After looking into this workaround I can confirm it doesn't work on Windows Phone 8.1 Runtime Apps.

    Effect is the same as trying to set the Binding within the ItemContainerStyle setter.

    Are there any other alternatives?

    Wednesday, October 22, 2014 8:10 PM
  • You could always handle the Loaded event for the root element in your ItemTemplate and use a visual tree helper to find the ListBoxItem. Please refer to the following example which hides the first item in the ListView, i.e. the container for the MyItem object with its Hide property set to true:

    public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
    
                lv.ItemsSource = new List<MyItem> { new MyItem { Name = "1", Hide = true }, new MyItem { Name = "2" } };
            }
    
            private void StackPanel_Loaded(object sender, RoutedEventArgs e)
            {
                StackPanel sp = sender as StackPanel;
                if (sp != null)
                {
                    ListViewItem lvi = FindParent<ListViewItem>(sp);
                    if (lvi != null)
                    {
                        MyItem dataObject = sp.DataContext as MyItem;
                        if (dataObject != null)
                            lvi.Visibility = dataObject.Hide ? Visibility.Collapsed : Visibility.Visible;
                    }
                }
            }
    
            private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
            {
                var parent = VisualTreeHelper.GetParent(dependencyObject);
    
                if (parent == null) return null;
    
                var parentT = parent as T;
                return parentT ?? FindParent<T>(parent);
            }
    }
    

    <ListView x:Name="lv">
                <ListView.Resources>
                    <local:MyConverter x:Key="conv"/>
                </ListView.Resources>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Loaded="StackPanel_Loaded">
                        <TextBlock Text="{Binding}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
    
    Please remember to mark helpful posts as answer and/or helpful.
    Wednesday, October 22, 2014 8:34 PM