1

I have create a DataTemplate for my Component object. I added DataTrigger to determine if the component should be visible or not. Essentially we have filters and the code checks those filters to determine if the component should be Visible or Collapse. The issue I have is that I want the trigger to set the visibility to "Collapse" or "Visible" of the parent container, i.e a ListBoxItem. The code works but sets it at the Border instead.

The template starts like this:

   <DataTemplate DataType="{x:Type local:Component}">
                <Border .....

I am providing the code for my Trigger and I'll explain what I tried below without success.

        <DataTemplate.Triggers>
            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource TrueWhenComponentIsVisible}">
                        <Binding Path="Type" />
                        <Binding Path="Dependency"/>
                        <Binding Path="SelectedType" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}"/>
                        <Binding Path="SelectedDepencency" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}"/>
                    </MultiBinding>
                </DataTrigger.Binding>
                <DataTrigger.Setters>
                    <Setter Property="Visibility" Value="Visible"></Setter>
                </DataTrigger.Setters>
            </DataTrigger>

            <DataTrigger Value="False">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource TrueWhenComponentIsVisible}">
                        <Binding Path="Type" />
                        <Binding Path="Dependency"/>
                        <Binding Path="SelectedType" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}"/>
                        <Binding Path="SelectedDepencency" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}"/>
                    </MultiBinding>
                </DataTrigger.Binding>
                <DataTrigger.Setters>
                    <Setter Property="Visibility" Value="Collapsed"></Setter>
                </DataTrigger.Setters>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

For the Setter Property

<Setter Property="Visibility" Value="Collapsed"></Setter>

I attempted to use the binding to get the listboxitem like this:

 <Setter Property="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}, Path=Visibility}" Value="Collapsed"></Setter>

I get this error when I try to run it, so I assume I can't use binding there at all and need a different approach?

A 'Binding' cannot be set on the 'Property' property of type 'Setter'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject
gmang
  • 435
  • 1
  • 6
  • 20
  • I would recommend investigating `ListCollectionView`. Your `ListBox` can then use a view as a source and specify filters in code behind. It is much cleaner then attempting to do it at the xaml level. – Julien Mar 07 '14 at 19:09
  • What is wrong with setting visibility at the Border? – paparazzo Mar 07 '14 at 19:24
  • 2
    As far as I know, `Binding` does not work in `Setter.Property`. You must specify a static value in the property. – Anatoliy Nikolaev Mar 07 '14 at 19:34
  • 2
    Saying `` is the equivilant of saying `myItem.Visibility = Visibility.Collapsed`. You cannot use a binding for the `Visibility` property like this. – Rachel Mar 07 '14 at 19:59
  • Hi Julien, I totally agree with you. The reason I went with XAML is that it is a recursive list of Category and Components and datatrigger seemed like a better approach but filtering in the code behind is what I may end up doing. – gmang Mar 07 '14 at 20:01

2 Answers2

2

Worked for me.
Don't know why it did not work for you?

<ListBox x:Name="lb" ItemsSource="{Binding}" DisplayMemberPath="Text">
    <ListBox.Resources>
        <Style TargetType="ListBoxItem">
            <Setter Property="Visibility" Value="{Binding Path=Vis}" />
        </Style>
    </ListBox.Resources>
</ListBox>

public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.DataContext = this;
        InitializeComponent();
        List<TextVis> TextViss = new List<TextVis>();
        TextVis tv1 = new TextVis();
        tv1.Text = "tv1";
        tv1.Vis = System.Windows.Visibility.Hidden;
        TextViss.Add(tv1);
        TextVis tv2 = new TextVis();
        tv2.Text = "tv2";
        tv2.Vis = System.Windows.Visibility.Visible;
        TextViss.Add(tv2);
        lb.ItemsSource = TextViss;
    }
    public class TextVis
    {
        public string Text { get; set; }
        public Visibility Vis { get; set; }
    }
}
paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • The problem I have with the style is that I don't have access to my DataContext properties. This is why I added a data trigger. If you notice above, I wrote a IMultiValueConverter to determine "True" or "False" if the component should show – gmang Mar 07 '14 at 19:41
  • Do you have the code sample of what you tried? I'll give it a shot! So You can access the properties of the DataContext ? – gmang Mar 07 '14 at 19:57
2

I want the trigger to set the visibility to "Collapse" or "Visible" of the parent container, i.e a ListBoxItem

Change the ItemContainerStyle, like this:

<ListBox ...>
   <ListBox.ItemContainerStyle>
      <Style TargetType="ListBoxItem">
         <Style.Triggers>

             <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource TrueWhenComponentIsVisible}">
                        <Binding Path="Type" />
                        <Binding Path="Dependency"/>
                        <Binding Path="SelectedType" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}"/>
                        <Binding Path="SelectedDepencency" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}"/>
                    </MultiBinding>
                </DataTrigger.Binding>

                <Setter Property="Visibility" Value="Visible"/>
            </DataTrigger>
         </Style.Triggers>
      </Style>
   </ListBox.ItemContainerStyle>
</ListBox>

BTW, you should really create a proper ViewModel and move all this logic to the ViewModel level instead of so much MultiBinding and Converter-based stuff.

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • The only issue with code provided is I always get "DepencencyProperty.UnsetValue" in the Converter, do you know why? ...and yes I will refactor to use ViewModel eventually, so thanks! – gmang Mar 07 '14 at 20:20
  • 1
    @gmang I have gotten that before with MultiBinding Converter. There is no guaranteed order to binding evaluation and sometimes the converter fires before the properties are set. But it never seems to happen with a Single Converter. Test for null and assign as best you can. Lots of times it will come back hit the converter after the binding are done. – paparazzo Mar 07 '14 at 20:25