Search code examples
c#wpfxamlattached-properties

How to set visibility of Button in xaml Style ControlTemplate based on presence of DataGrid child


I have a Style declaration in xaml for a GroupBox. This Style declaration includes a ControlTemplate that includes a Button. I would like the Button visibility to be dependent on whether a DataGrid will be a child of the GroupBox. The GroupBox is dynamically built in code-behind.

In the code-behind, a boolean value determines whether a DataGrid will be a child of the GroupBox at the time when the GroupBox is created.

I thought about using a boolean Attached Property (AP) for the GroupBox, that would specify whether a DataGrid would be the child of the GroupBox, but I'm not sure how this would be declared in the Style declaration (or if I would even declare an AP there), or how I could use the AP in the code-behind.

How do I set the Visibility property of the Button based on the presence of a DataGrid?

Could someone please give me a simple example of how I would set this up?

Any help is greatly appreciated!


Solution

  • The usual way of doing this is with a DataTrigger, although you can also do it with converter. Either way, you'll need to bind to that boolean value in your code behind. I'll assume you've set the window to be it's own DataContext, so just do something like this:

    <Button Content="Press Me" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding YourBooleanValue}" Value="False">
                        <Setter Property="Visibility" Value="Hidden" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding YourBooleanValue}" Value="True">
                        <Setter Property="Visibility" Value="Visible" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    

    UPDATE:

    Ok, based on the additional info you've provided below I think I understand now what you're trying to do. Please correct me if any of this is wrong, but it sounds like you're creating GroupBox's an given some of them a DataGrid as a child:

            var groupBox1 = new GroupBox();
            this.thePanel.Children.Add(groupBox1);
    
            var groupBox2 = new GroupBox();
            var dataGrid = new DataGrid();
            dataGrid.Columns.Add(new DataGridTextColumn { Header = "Column1" });
            dataGrid.Columns.Add(new DataGridTextColumn { Header = "Column2" });
            dataGrid.Columns.Add(new DataGridTextColumn { Header = "Column3" });
            groupBox2.Content = dataGrid;
            this.thePanel.Children.Add(groupBox2);
    

    Then in your style you have a ContentControl for GroupBoxes containing a button, and you only want that button to be visible on groupboxes that have a DataGrid for a child? If that's the case then you can do it easily enough with a converter. You bind the button's Visibility property to the GroupBox's content and then you use a converter to convert from that to a Visibility setting:

        <conv:ChildVisibilityConverter x:Key="ChildVisibilityConverter" />
    
        <Style TargetType="{x:Type GroupBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GroupBox">
                        <Border BorderBrush="Black" BorderThickness="1" CornerRadius="10" Margin="5" Padding="5" >
                            <StackPanel Orientation="Vertical">
                                <TextBlock Text="Group Box" />
                                <Button Content="Click Me" HorizontalAlignment="Left" VerticalAlignment="Top"
                                        Visibility="{TemplateBinding Content, Converter={StaticResource ChildVisibilityConverter}}" />
                                <ContentPresenter />
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    The actual converter itself simply looks at what it's been given (i.e. the GroupBox's Content), checks its type and returns the Visibility accordingly:

    public class ChildVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return Visibility.Hidden;
            return (value.GetType() == typeof(DataGrid))
                ? Visibility.Visible
                : Visibility.Hidden;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    So for that block of code I posted above you'll only see the button in the second GroupBox:

    enter image description here

    Does that answer the question?