You asked about
IValueConverter
... Here is how you would do it with a multi-purpose
VisibilityConverter
:
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return Visibility.Collapsed;
if (value is int) return (int)value == 0 ? Visibility.Collapsed : Visibility.Visible;
if (value is string) return string.IsNullOrEmpty((string)value) ? Visibility.Collapsed : Visibility.Visible;
if (value is bool) return (bool) value ? Visibility.Visible : Visibility.Collapsed;
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> DependencyProperty.UnsetValue;
}
Then to use:
<Window.Resources>
<local:VisibilityConverter x:Key="VisibilityConverter" />
</Window.Resources>
<Grid DataContext="{Binding ElementName=Window1}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0"
Visibility="{Binding Collection1.Count, Converter={StaticResource VisibilityConverter} }">
<TextBlock Text="Collection1"/>
</Grid>
<Grid Grid.Row="1"
Visibility="{Binding Collection2.Count, Converter={StaticResource VisibilityConverter} }">
<TextBlock Text="Collection2"/>
</Grid>
</Grid>
UPDATE
If you want to test multiple values, then you need to use a
IMultiValueConverter
:
public class MultiVisibilityConverter : IMultiValueConverter
{
public object Convert(object[]? values, Type targetType, object parameter, CultureInfo culture)
{
if (values is null) return Visibility.Collapsed;
if (values.OfType<int>().Any())
return values.Cast<int>().Any(x => x == 0) ? Visibility.Collapsed : Visibility.Visible;
if (values.OfType<string>().Any())
return values.Cast<string>().Any(string.IsNullOrEmpty) ? Visibility.Collapsed : Visibility.Visible;
if (values.OfType<bool>().Any())
return values.Cast<bool>().Any(x => !x) ? Visibility.Collapsed : Visibility.Visible;
return Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> new[] { DependencyProperty.UnsetValue };
}
Then to use:
<Window.Resources>
<local:MultiVisibilityConverter x:Key="MultiVisibilityConverter"/>
</Window.Resources>
<Grid Grid.Row="2">
<Grid.Visibility>
<MultiBinding Converter="{StaticResource MultiVisibilityConverter}">
<Binding Path="Collection1.Count" />
<Binding Path="Collection2.Count" />
</MultiBinding>
</Grid.Visibility>
<TextBlock Text="Collection 1 and 2"/>
</Grid>
Update #2
I re-read yor comments, and you want the option for all = 0; so here is an updated
IMultiValueConverter
with a selector parameter:
public class MultiVisibilityConverter : IMultiValueConverter
{
public object Convert(object[]? values, Type targetType, object? parameter, CultureInfo culture)
{
if (values is null) return Visibility.Collapsed;
bool isAny = parameter is null || (parameter is string && ((string)parameter).ToLower() != "all");
if (values.OfType<int>().Any())
return isAny
? values.Cast<int>().Any(x => x == 0)
? Visibility.Collapsed
: Visibility.Visible
: values.Cast<int>().All(x => x == 0)
? Visibility.Collapsed
: Visibility.Visible
if (values.OfType<string>().Any())
return isAny ?
values.Cast<string>().Any(string.IsNullOrEmpty)
? Visibility.Collapsed
: Visibility.Visible
: values.Cast<string>().All(string.IsNullOrEmpty)
? Visibility.Collapsed
: Visibility.Visible
if (values.OfType<bool>().Any())
return isAny
? values.Cast<bool>().Any(x => !x)
? Visibility.Collapsed
: Visibility.Visible
: values.Cast<bool>().All(x => !x)
? Visibility.Collapsed
: Visibility.Visible;
return Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> new[] { DependencyProperty.UnsetValue };
}
and to use:
<Grid Grid.Row="2">
<Grid.Visibility>
<MultiBinding Converter="{StaticResource MultiVisibilityConverter}"
ConverterParameter="All">
<Binding Path="Collection1.Count" />
<Binding Path="Collection2.Count" />
</MultiBinding>
</Grid.Visibility>
<TextBlock Text="Collection 1 and 2"/>
</Grid>
UPDATE #3 - attempt at C#5.0 compatibility
public class MultiVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null) return Visibility.Collapsed;
bool isAny = parameter == null || (parameter is string && ((string)parameter).ToLower() != "all");
if (values.OfType<int>().Any())
{
if (isAny)
{
return values.Cast<int>().Any(x => x == 0)
? Visibility.Collapsed
: Visibility.Visible;
}
else
{
return values.Cast<int>().All(x => x == 0)
? Visibility.Collapsed
: Visibility.Visible;
}
}
if (values.OfType<string>().Any())
{
if (isAny)
{
return values.Cast<string>().Any(string.IsNullOrEmpty)
? Visibility.Collapsed
: Visibility.Visible;
}
else
{
return values.Cast<string>().All(string.IsNullOrEmpty)
? Visibility.Collapsed
: Visibility.Visible;
}
}
if (values.OfType<bool>().Any())
{
if (isAny)
{
return values.Cast<bool>().Any(x => !x)
? Visibility.Collapsed
: Visibility.Visible;
}
else
{
return values.Cast<bool>().All(x => !x)
? Visibility.Collapsed
: Visibility.Visible;
}
}
return Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { DependencyProperty.UnsetValue };
}
}