User avatar
rmcq
Topic Author
Posts: 16
Joined: 18 Feb 2020, 23:31

New UserControl - Calling SetWidth / SetHeight on Inner Control Makes it Disappear

09 Jun 2020, 02:39

Hi team,

I'm having a problem trying to set the height/width of a control in my UserControl. Whenever I call SetWidth/Height AND the value changes, the control disappears. This happens on both the grid and image. It looks correct when I test in Blend.

The context:
- The UserControl is in the DataTemplate of some ListBoxes
- It's composed of two Grids and an Image.
- Of the two grids, one is for the "Highlighted" state and the other the "Unhighlighted" state. We go between these using Visual States. For now I've commented them all out so they shouldn't be having any effect.
- The two grids overlap. They both have a SkewTransform applied to the bottom-left corner. SkewTransform defaults to the top-left corner. To get a different corner I need to set the CenterX / CenterY values. I need my UserControl to be scalable for the different Listboxes. So I have to calculate these values in code.
- The 'Unhighlighted' grid height also changes. Some screens have it as 0.8* the height of the 'Highlighted' one. Sometimes they're the same height. This modifier is set with the DependencyProperty "UnhighlightedHeightMod". I'm applying this in code as well. Setting it via RowDefinitions did not appear correct in Blend or in-game. I don't know if you can bind RowDefinitions so they're different between instances.
- The image is the same height as the Unhighlighted grid in all instances.

I would appreciate any help.

Thanks,
R

Code simplified:
<UserControl
...
>
	<Grid>
		<VisualStateManager.VisualStateGroups>
			...visual state stuff...
		</VisualStateManager.VisualStateGroups>

		<Grid 
			x:Name="HighlightedGrid" 
		>
			<Rectangle
			>
				<Rectangle.Fill>
					<SolidColorBrush x:Name="HighlightedPathColourBrush" Color="Orange"/>
				</Rectangle.Fill>
			</Rectangle>
		</Grid>

		<Grid
			x:Name="UnhighlightedGrid"
		>
			<Rectangle
			>
				<Rectangle.Fill>
					<SolidColorBrush x:Name="UnhighlightedPathColourBrush" Color="Yellow"/>
				</Rectangle.Fill>
			</Rectangle>
		</Grid>

		<Grid>
			<Image 
				x:Name="Image"
				Source="{Binding ImagePath, Mode=OneWay}"
				Stretch="Uniform"
				VerticalAlignment="Bottom"
			/>
		</Grid>
	</Grid>
</UserControl>
void TheUserControl::InitialiseComponent()
{
...
	SizeChanged() += MakeDelegate(this, &TheUserControl::HandleSizeChanged);
	Resize(1920, 1080);
...
}

void TheUserControl::HandleSizeChanged(BaseComponent* baseComponent, const Noesis::SizeChangedEventArgs& args)
{
	Noesis::Size newSize = args.sizeChangedInfo.newSize;
	ResizeAndSkew(newSize.width, newSize.height);
}

void TheUserControl::ResizeAndSkew(float fullWidth, float fullHeight)
{
	float angleX = -10.f;
	float absAngle = fabs(angleX);
	float triangleAngle = 90.f - fabs(absAngle);
	float triangleAngleRadians = DEGREES_TO_RADIANS(triangleAngle);
	float angleTangent = tanf(triangleAngleRadians);
	float triangleSpace = fullHeight / angleTangent;
	float minGridWidth = fullWidth * 0.64f;
	float gridWidth = paMath::max(fullWidth - triangleSpace, minGridWidth);
	float playerWidth = fullWidth;

	float highlightedCentreY = fullHeight;
	float heightMod = GetValueUnhighlightedHeightMod();
	float unhighlightedCentreY = fullHeight * heightMod;

	m_PlayerImage->SetHorizontalAlignment(Noesis::HorizontalAlignment::HorizontalAlignment_Left);
	m_PlayerImage->SetVerticalAlignment(Noesis::VerticalAlignment::VerticalAlignment_Bottom);
	
	m_PlayerImage->SetHeight(unhighlightedCentreY);
	m_PlayerImage->SetWidth(playerWidth);

	m_HighlightedGrid->SetWidth(gridWidth);
	m_HighlightedGrid->SetHeight(highlightedCentreY);
	m_HighlightedGrid->SetHorizontalAlignment(Noesis::HorizontalAlignment::HorizontalAlignment_Left);
	m_HighlightedGrid->SetVerticalAlignment(Noesis::VerticalAlignment::VerticalAlignment_Bottom);
	Noesis::SkewTransform* skew = new Noesis::SkewTransform(angleX, 0.f);
	skew->SetCenterY(highlightedCentreY);
	m_HighlightedGrid->SetRenderTransform(skew);

	m_UnhighlightedGrid->SetWidth(gridWidth);
	m_UnhighlightedGrid->SetHeight(unhighlightedCentreY);
	m_UnhighlightedGrid->SetHorizontalAlignment(Noesis::HorizontalAlignment::HorizontalAlignment_Left);
	m_UnhighlightedGrid->SetVerticalAlignment(Noesis::VerticalAlignment::VerticalAlignment_Bottom);

	skew = new Noesis::SkewTransform(angleX, 0.f);
	skew->SetCenterY(unhighlightedCentreY);
	m_UnhighlightedGrid->SetRenderTransform(skew);
}
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: New UserControl - Calling SetWidth / SetHeight on Inner Control Makes it Disappear

09 Jun 2020, 20:10

Hi,

What Panel is the ListBox using to place the items? The default VirtualizingStackPanel?
If it is using a stack panel, the height of each item would be determined by the minimum required height of your UserControl. In this case that depends on the height of the image if there aren't any other elements in the control with a explicit height. Could you verify if args.sizeChangedInfo.newSize.height is 0 when inner controls disappear?

I created a test following your indications trying to reproduce the problem without success. Could you please create a small sample where you can reproduce it?

On a side note, it would be better if your Highlighted/Unhighlighted grids already have the SkewTransform defined in xaml and you just modify it, otherwise you are creating new objects everytime size changes.
Noesis::SkewTransform* skew = (Noesis::SkewTransform*)m_HighlightedGrid->GetRenderTransform();
skew->SetAngleX(angleX);
skew->SetCenterY(highlightedCentreY);
Related to this transform, I think you can also use RenderTransformOrigin property instead of calculating the CenterY in code, because that property is relative to element's size, so you can just set it to "0, 1" if you want the transform origin to be in the bottom-left corner of the element.

And looking at the code I see a possible memory leak on object creation:
Noesis::SkewTransform* skew = new Noesis::SkewTransform(angleX, 0.f);
m_HighlightedGrid->SetRenderTransform(skew);
This is leaking if you don't manually release the initial reference because when the transform is set in the grid it adds its own reference.

You should be using Ptr and MakePtr to avoid this:
Noesis::Ptr<Noesis::SkewTransform> skew = Noesis::MakePtr<Noesis::SkewTransform>(angleX, 0.f);
m_HighlightedGrid->SetRenderTransform(skew);

Who is online

Users browsing this forum: No registered users and 12 guests