Click here to Skip to main content
15,887,350 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi, I'm trying to follow MVVM pattern and want to hide a certain grid in my WPF app where there are two conditions e.g. right now I've something like

What I have tried:

C#
<Grid.Resources>
	<Style
		TargetType="{x:Type Grid}">
		<Style.Triggers>
			<DataTrigger Binding="{Binding collection1.Count}" Value="0">
				<Setter Property="Visibility" Value="Collapsed"/>
			</DataTrigger>
		</Style.Triggers>
	</Style>
</Grid.Resources>


Now there is another check that I want to do in the above code, something like if Binding="{Binding collection1.Count}" OR Binding="{Binding collection2.Count}" either one of thems value is 0 then implement <Setter Property="Visibility" Value="Collapsed"/>

How can I do this using datatrigger (if possible at all)? Can a IValueConverter be used to do this ? How ?
Posted
Updated 3-May-23 5:14am

For something this simple, you just need to add two triggers:
XAML
<Style.Triggers>
    <DataTrigger Binding="{Binding collection1.Count}" Value="0">
        <Setter Property="Visibility" Value="Collapsed" />
    </DataTrigger>
    <DataTrigger Binding="{Binding collection2.Count}" Value="0">
        <Setter Property="Visibility" Value="Collapsed" />
    </DataTrigger>
</Style.Triggers>
If either collection is empty, the grid will be hidden.

For something more complicated, add a property to your view-model to indicate whether or not the grid should be shown. You would need to ensure that you raised the PropertyChanged event for that property whenever any of the values it depended on changed.
 
Share this answer
 
Comments
Member 12692000 3-May-23 11:06am    
Thanks. What about doing when both the bindings value are 0 only then the grid will be hidden ?
Richard Deeming 3-May-23 11:12am    
As I said, for something more complicated like that, you'll need to add a property to your view-model.
You asked about IValueConverter... Here is how you would do it with a multi-purpose VisibilityConverter:
C#
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; // not required - one-way conversion
}

Then to use:
XML
<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:
C#
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 }; // not required - one-way conversion
}

Then to use:
XML
<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:
C#
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 }; // not required - one-way conversion
}

and to use:
XML
<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
C#
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 };
    }
}
 
Share this answer
 
v5
Comments
Member 12692000 4-May-23 1:47am    
I wish I could test your update 2 as it is exactly what I was looking for but I am unable to as I'm running c#5.0 unfortunately.
Graeme_Grant 4-May-23 3:21am    
Why C# 5.0? It should be fine. I was using IMultiValueConverter with .Net Framework 3.5 released 19/11/2007 (.NET Framework version history - Wikipedia[^]) and c# 5.0 was released in August, 2012 (The history of C# - C# Guide | Microsoft Learn[^]). Linq too was released back in 2007 with .Net Framework 3.5 (Language Integrated Query - Wikipedia[^]).

You can check here: IMultiValueConverter.Convert(Object[], Type, Object, CultureInfo) Method (System.Windows.Data) | Microsoft Learn[^]

You may need to look at the c# syntax used. I do not have c# 5.0 on my dev machine, but I'll try and make it compatible with C#5.0. There is nothing complicated with the code above.
Member 12692000 4-May-23 3:29am    
But I'm getting tons of errors starting frompublic object Convert(object []? values...
Graeme_Grant 4-May-23 3:36am    
Check the update #3.
Member 12692000 4-May-23 3:47am    
Thanks.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900