question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[GroupBox] Missing

See original GitHub issue

There is no GroupBox like In WPF. Although it’s not essential, this control is useful to label groups of controls.

TEMPORARY TRICK: Although it doesn’t exist, it can be emulated with a HeaderedContentControl with a custom Style:

        <Style Selector="HeaderedContentControl">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border>
                            <StackPanel>
                                <ContentPresenter TextBlock.FontWeight="Bold" Content="{TemplateBinding Header}" />
                                <Border
                                    BorderBrush="{TemplateBinding Background}"
                                    BorderThickness="2"
                                    CornerRadius="5">
                                    <ContentPresenter Content="{TemplateBinding Content}" />
                                </Border>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:8
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

24reactions
derekantricancommented, Sep 18, 2020

For people who look at this in the future (which I’m sure will be the case unless one day Avalonia officially implements GroupBox), the workaround by @SuperJMN is great - you just have to assign the Border property, which is different from how normal WPF works (I think it’s just black by default):

image

        <Style Selector="HeaderedContentControl">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border>
                            <StackPanel>
                                <ContentPresenter TextBlock.FontWeight="Bold" Content="{TemplateBinding Header}" />
                                <Border
                                    BorderBrush="{TemplateBinding Background}"
                                    BorderThickness="2"
                                    CornerRadius="5">
                                    <ContentPresenter Content="{TemplateBinding Content}" />
                                </Border>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <HeaderedContentControl Header="Header" Background="Black">
          <TextBlock Text="text" Margin="5"/>
        </HeaderedContentControl>

But if you want something a little more classic-style, I created this:

image

    <Style Selector="HeaderedContentControl">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate>
            <Grid>
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
              </Grid.ColumnDefinitions>
              <Border ZIndex="1" Padding="5,0,5,0" Background="White" Margin="5,0,0,0">
                <TextBlock TextBlock.FontWeight="Bold" Text="{TemplateBinding Header}" />
              </Border>
              <Border Grid.RowSpan="2" Grid.ColumnSpan="2" Margin="0,10,0,0"
                  BorderBrush="{TemplateBinding Background}"
                  BorderThickness="1">
                <ContentPresenter Content="{TemplateBinding Content}" />
              </Border>
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
0reactions
BinTosscommented, Jul 11, 2023

I’ll edit this issue to hide the WIP portion when its main issues are resolved.

Discussion found here.


2023-07-11

image

Notes:

  • Now targeting Avalonia 11.0.0
  • Requires a Converter class to convert Bounds properties (Rect) to a Clip property (Geometry).
    • When the Bounds are passed as Data Bindings with the Converter to a CombinedGeometry in AXAML, the CombinedGeomtry’s Geometry1 and Geometry2 properties will observe the source Bounds properties for changes and will call the converter every time the Bounds change.
  • If copying to your project, ensure you include the AXAML file in the project file e.g. <AvaloniaResource Include="GUI\Styles\*.axaml" />. Do not include AXAML files which have code-behind.
  • This style’s sample are made with Avalonia.Themes.Simple. When using the Simple theme, ensure it’s added and untrimmed e.g. <PackageReference Include="Avalonia.Themes.Simple" Version="11.0.0" /> and <TrimmerRootAssembly Include="Avalonia.Themes.Simple" />

Fixed:

  • Header erroneously clipping Content has been resolved via workaround. The Border of GBContent is now invisible and not clipped. The visible, clipped border is now a separate element containing an invisible rectangle to ensure it has the same size as GBContent.

Known Issues:

  • Resized Border does not render past its initial Bounds.
  • Header text seems slightly offset on the Y axis.

TODO:

  • Refactor to ThemeResource
  • Get sample image for “classic” style with Fluent theme
  • Get sample images for Simple- and Fluent- themed “modern” style.
  • Consider making WPF-/MahApps.Metro-inspired theme
GroupBoxSimpleClassic.axaml
<Styles
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:CompileBindings="True"
    xmlns:conv="clr-namespace:HXE.GUI.Converters;assembly=HXE">

    <Style Selector="HeaderedContentControl">

        <SimpleTheme />

        <Style.Resources>
            <conv:RectGeometryConverter x:Key="rectConv" />
            <Thickness x:Key="BorderMargin">0,10,0,0</Thickness>
            <Thickness x:Key="BorderPadding">5,10,5,5</Thickness>

        </Style.Resources>

        <Setter
            Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid Name="GBGrid">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>

                        <TextBlock Name="GBHeaderText"
                            Margin="5,0,0,0"
                            Padding="5,0,5,0"
                            ZIndex="1"
                            TextBlock.FontWeight="Bold" Text="{TemplateBinding Header}">
                        </TextBlock>

                        <Border Name="GBBorder"
                            Grid.RowSpan="2" Grid.ColumnSpan="2"
                            Margin="{DynamicResource BorderMargin}"
                            Padding="{DynamicResource BorderPadding}"
                            BorderBrush="{TemplateBinding Foreground}"
                            BorderThickness="1">
                            <Rectangle
                                Height="{Binding #GBContent.Height}"
                                Width="{Binding #GBContent.Width}" />
                            <Border.Clip>
                                <CombinedGeometry
                                    GeometryCombineMode="Exclude"
                                    Geometry1="{Binding #GBGrid.Bounds, Mode=OneWay, Converter={StaticResource rectConv}}"
                                    Geometry2="{Binding #GBHeaderText.Bounds, Mode=OneWay, Converter={StaticResource rectConv}}" />
                            </Border.Clip>
                        </Border>

                        <Border Name="GBContent"
                            Grid.RowSpan="2" Grid.ColumnSpan="2"
                            Margin="{DynamicResource BorderMargin}"
                            Padding="{DynamicResource BorderPadding}"
                            BorderThickness="0">

                            <ContentPresenter Content="{TemplateBinding Content}" />
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Styles>
RectGeometryConverter.cs
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Media;

namespace HXE.GUI.Converters;

public class RectGeometryConverter : IValueConverter
{
    public static readonly RectGeometryConverter Instance = new();

    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value is Rect rect)
            return new RectangleGeometry(rect);

        // converter used for the wrong type
        return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
    }

    public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value is RectangleGeometry rectangle)
            return rectangle.Rect;

        // converter used for the wrong type
        return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
    }

}

2023-06-26

@derekantrican’s examples are great, but the Classic style in that example will not adapt to Theme or Style changes i.e. Header background will remain solid white when the “real” background changes. I’ve considered two solutions to this. One utlizes the Border’s Clip property. The other utilizes the Border’s OpacityMask. I’m attempting the former, but I’m struggling to make the Clip geometry recalculate when the source Bounds change. Both will likely require classes for conversions and/or observers.

Border.Clip = BoundsA - BoundsB


(Click to see images) At one point, I was excluding GBHeader.Bounds (GBHeader being the Border containing the text block in the original example) from GBContent.Bounds, but an unexpectedly large part of the latter's Border is clipped despite the resulting geometry not affecting that region according the Dev Tools.
(Click to see images) However, I now exclude GBHeaderText.Bounds from GBGrid.Bounds to avoid that particular issue.

This implementation currently has two issues.

  1. The CombinedGeometry assigned to GBContent.Clip is not recalculated when the Rect-value Bounds it was created from have changed.
  2. The CombinedGeomtry assigned to GBContent.Clip partially obscures the presented contents. I believe this could be remedied by getting the TransformBounds, but the lack of this property in my Avalonia 11.0.0-rc1.1 application’s Dev Tools window indicates it no longer exists or may be inaccessible under certain conditions. The suspected issue is that two Bounds have different origin points relative to the window, so excluding one Bounds from the other will result in one being offset from its expected position in the CombinedGeometry

GroupBoxClassic.axaml

<Styles
	xmlns="https://github.com/avaloniaui"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://github.com/avaloniaui ../../../AvaloniaSchema-11.0.0.xsd"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:CompileBindings="True"
	xmlns:conv="clr-namespace:HXE.GUI.Converters;assembly=HXE">

	<!-- AvaloniaSchema is generated by Avant Garde -->

	<Style
		Selector="HeaderedContentControl">
		<SimpleTheme />
		<Style.Resources>
			<conv:RectGeometryConverter x:Key="rectConv" />
		</Style.Resources>
		<Setter
			Property="Template">
			<Setter.Value>
				<ControlTemplate>
					<Grid Name="GBGrid">
						<Grid.RowDefinitions>
							<RowDefinition Height="Auto" />
							<RowDefinition Height="*" />
						</Grid.RowDefinitions>
						<Grid.ColumnDefinitions>
							<ColumnDefinition Width="Auto" />
							<ColumnDefinition Width="*" />
						</Grid.ColumnDefinitions>


						<TextBlock Name="GBHeaderText"
							Margin="5,0,0,0"
							Padding="5,0,5,0"
							TextBlock.FontWeight="Bold" Text="{TemplateBinding Header}">
							<TextBlock.Bounds />
						</TextBlock>

						<Border Name="GBContent"
							Grid.RowSpan="2" Grid.ColumnSpan="2"
							Margin="0,10,0,0"
							Padding="5,10,5,5"
							BorderBrush="{TemplateBinding Foreground}"
							BorderThickness="1"
							Clip="{Binding}">
							<Border.Clip>
								<CombinedGeometry x:DataType="Rect"
									GeometryCombineMode="Exclude"
									Geometry1="{Binding ElementName=GBGrid, Path=Bounds, Mode=OneWay, Converter={StaticResource rectConv}}"
									Geometry2="{Binding ElementName=GBHeaderText, Path=Bounds, Mode=OneWay, Converter={StaticResource rectConv}}">
								</CombinedGeometry>
							</Border.Clip>
							<ContentPresenter Content="{TemplateBinding Content}" />
						</Border>
					</Grid>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
</Styles>

RectGeometryConverter.cs

using System;
using System.Globalization;
using Avalonia;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Media;

namespace HXE.GUI.Converters;

public class RectGeometryConverter : IValueConverter
{
    public static readonly RectGeometryConverter Instance = new();

    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value is Rect rect)
            return new RectangleGeometry(rect);

        // converter used for the wrong type
        return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
    }

    public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value is RectangleGeometry rectangle)
            return rectangle.Rect;

        // converter used for the wrong type
        return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
    }

}

Read more comments on GitHub >

github_iconTop Results From Across the Web

Groupbox disappeared in Visual Studio C# Winform
I've created a GroupBox with some buttons, topdowns and labels in it. But in the preview it disappeared. I still have the code...
Read more >
groupbox missing from my toolbox
associated with "System.Windows.Forms" do show up in my VS8 toolbox. Currently I am using a panel to group controls. It is missing a...
Read more >
Panel or Groupbox is missing in toolBox
Windows Forms designer in Visual Studio 16.5 Preview 1 Net Core 3.1 - Panel or Groupbox is missing in toolBoxClosed - Not Enough...
Read more >
Solved: Edit Group box disappeared - REVIT 2011
Solved: When I'm in the Group Edit mode, the box disappeared and I have no way to close the group. This is in...
Read more >
Group Box Header Titles Do Not Display on Employee Event ...
On the Plan Type page of the Employee Event Details component, the group box labels are missing; instead they display as "Group Box...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found