Search code examples
wpfbindingdatagriddatatemplatemultidatatrigger

How to bind a parents property to the child elements datatemplate


I need to bind the RowStyle property of my DataGrid to the Visibility if the DataGrids childrens through a converter. The thing is that the children exists in a DataTemplate. My code below is a simplified version of what I am doing right now, so It might not make much sence. But anyway:

<DataGrid Name="dataGrid"
              ItemsSource="{Binding Path=ListOfData}"
              RowStyle="{StaticResource DataGridRowStyle}"
              >
        <DataGrid.RowDetailsTemplate>
              <DataTemplate>
                    <StackPanel>
                         <TextBlock Name="textBlock" Source={Binding Path=Title}
                         <Image Name="image" Source="{Binding Path=Image}"/>
                    </StackPanel>
              </DataTemplate>
        </DataGrid.RowDetailsTemplate>
  </DataGrid>

The thing is, that the TextBlock and Image can individually get collapsed. If both are collapsed, I need the DataGridRow to collapse or hide so you wont see it in the grid. My plan was to define a RowStyle named 'DataGridRowStyle'. The style will get triggered by the TextBlock and Images's Visibility property and set the RowStyle's Visibility to collapsed.

  <Style TargetType="{x:Type DataGridRow}" x:Key="DataGridRowStyle">
    <Setter Property="Visibility" Value="Visible" />
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Value="True">
                    <Condition.Binding>
                        <MultiBinding Converter="{StaticResource VisibilityConverter}">
                            <Binding ElementName="textBlock" Path="Visibility" />
                            <Binding ElementName="image" Path="Visibility" />
                        </MultiBinding>
                    </Condition.Binding>
                </Condition>
            </MultiDataTrigger.Conditions>
            <Setter Property="Visibility"  Value="Collapsed"/>
        </MultiDataTrigger>
    </Style.Triggers>
</Style>

Unfortunately, I get a warning in runtime, where System.Data can't fint my textBlock or image element. I guess you can't bind to a DataTemplate or what do I do wrong? Can I somehow do the same differently?


Solution

  • you indeed cannot bind to your dataTemplate here, since it is out of the RowStyle's scope.

    I would do it in an other manner:

    1. As I see it, you should be able to determine in your ItemViewModel if the TextBox and the image are both collapsed at the same time
    2. Add a property to your ItemViewModel ('VisibilityProperty' for instance) and set it to 'Collapsed' when they both the TextBox and Image are collapsed.
    3. Bind the VisibilityProperty of your DataGridRow to this property of your ItemViewModel through the RowStyle.

    this should do it

    edit: if you cannot change your itemViewModel, you have an other option (quite ugly though):

    bind the Row's Visibility to the Item itself and use a converter to look for the items children and see if they are collapsed at runtime.

    something along those lines:

    <Style TargetType="{x:Type DataGridRow}" x:Key="DataGridRowStyle">
        <Setter Property="Visibility" Value="{Binding Converter=MyRowViewModelToVisibilityconverter}" />
    </Style>
    

    and your converter's code you have the item obviously, so just look for the TextBox's ViewModel and the Image's Viewmodel and see if they would collapse the Image & TextBox, then return the Visibility Accordingly:

    public class MyRowViewModelToVisibilityconverter: MarkupExtension, IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var item = value as ItemViewModel;
            bool isImageCollapsed = false, isTextBoxCollapsed = false;
    
            // Look into your ItemViewModel for the properties inducing a Visibility=Collapsed on the Image and the TextBox
    
            return (isImageCollapsed && isTextBoxCollapsed) ? Visibility.Collapsed : Visbility.Visible;
    
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return new MyRowViewModelToVisibilityconverter();
        }
    }