7

I'm trying to do an "empty list to visibility converter" for WPF. This is an IValueConverter that takes an object ( that should be a list ) and if the list is empty (or if the passed object is null ) it should return Visibility.Collapsed; if the list is not empty it should return Visibility.Visibile;

I plan to use this for a datagrid. The plan is to make the datagrid invisible (collapsed) whenever the list given to the ItemsSource is an empty list or a null.

<my:DataGrid 
                    Name="dataGridAuxiliaryTools"
                    Style="{StaticResource DataGridStyle}"
                    CellStyle="{StaticResource DataGridCellStyle}"
                    ColumnHeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
                    ItemsSource="{Binding Path=Items}"
                    IsReadOnly="False"
                    Visibility="{Binding Path=Items, 
                    Converter={StaticResource emptyListToVisibilityConverter}}"
 </my:DataGrid>

I wrote the EmptyListToVisibilityConverter as follows:

public class EmptyListToVisibilityConverter : IValueConverter
    {
    public object Convert(object value, Type targetType, object parameter,
                          CultureInfo culture)
    {
        if (value == null)
        {
            return Visibility.Collapsed;
        }
        else if (value is IList<Object>)
        {
            if ((value as IList<Object>).Count == 0)
            {
                return Visibility.Collapsed;
            }
            else
            {
                return Visibility.Visible;
            }
        }
        else
        {
            return Visibility.Visible;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter,
                              CultureInfo culture)
    {
        throw new NotImplementedException();
    }

This works well when Items is given as null but when Items is given as a List it does not work ... I think that the code bellow is not correct and cannot detect if "value" is a list or not ... Any hints ?

if (value is IList<Object>)
            {
                if ((value as IList<Object>).Count == 0)
                {
                    return Visibility.Collapsed;
                }
                else
                {
                    return Visibility.Visible;
                }

Any hints on how to do this ?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
MadSeb
  • 7,958
  • 21
  • 80
  • 121

6 Answers6

12

You can't cast your list to IList <Object>, but you can cast it to ICollection, and then use ICollection.Count : see http://devw.wordpress.com/2011/07/18/empty-list-visibility-converter/

public class EmptyListVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return Visibility.Collapsed;
        else
        {
            ICollection list = value as ICollection;
            if (list != null)
            {
                if (list.Count == 0)
                    return Visibility.Collapsed;
                else
                    return Visibility.Visible;
            }
            else
                return Visibility.Visible;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {
        throw new NotImplementedException();
    }
}
<ListBox x:Name=”NameChoiceListBox”
         ItemsSource=”{Binding NamesList}”
         SelectedItem=”{Binding SelectedName, Mode=TwoWay}”
         ItemTemplate=”{StaticResource DataTemplateNameChoice}”
         Visibility=”{Binding NamesList, Converter={StaticResource EmptyListVisibilityConverter}}”>
Dave
  • 8,163
  • 11
  • 67
  • 103
Hrb47
  • 136
  • 1
  • 2
5

I think its quite straight forward, here you go:

  public class NullOrEmptyCollectionToVisibilityConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      if (value == null) return Visibility.Collapsed;

      var collection = value as ICollection;
      return collection != null ? (collection.Count == 0 ? Visibility.Collapsed : Visibility.Visible) : Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
      throw new NotImplementedException();
    }
  }

Hoping wil help, thanks! - Shams

user3565920
  • 94
  • 1
  • 2
5

I guess the problem is, that the collection object stays the same, when you add or remove items from it. So the binding does not update the value and the converter is not called.

Adam Lear
  • 38,111
  • 12
  • 81
  • 101
Christian Moser
  • 1,871
  • 20
  • 10
2

My guess is that it's because of the fact that you're using IList<Object> in the converter but your actual collection is an IList<SomethingElse>. See, IList is not covariant so you can't just convert any IList<T> to an IList<Object>. My suggestion will be to try and use IEnumerable<object> in the converter instead and use the Count() extension method to determine the number of items in the collection.

ASanch
  • 10,233
  • 46
  • 32
  • I used "Any" rather than Count()>0 > ((IEnumerable) value).Any()? Visibility.Visible: Visibility.Collapsed; – TobyEvans Jan 24 '13 at 11:55
2

C# version 7 supports pattern matching. Now you can write:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    switch (value)
    {
        case null:
            return Visibility.Collapsed;
        case ICollection list:
            return list.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
    }

    return Visibility.Visible;
}
richej
  • 834
  • 4
  • 21
0

A better alternative is to use ObservableCollection and then bind to its Count property: WPF Converters and ObservableCollections

Sasha Yakobchuk
  • 471
  • 6
  • 12