Page 1 of 1

Changing Color of Textblock Dynamically and a few other Q's.

Posted: 09 Dec 2020, 09:58
by TimTheToad
I'm trying to change the color of a textblock during runtime, depending on team colors in our game.

The TextBlock is defined in .Xaml via a UserControl which is invoked when a player dies/scores.

.Xaml Code:
<UserControl x:Class="CrazyCanvas.PromptGUI"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:CrazyCanvasNoesisGUI"
             mc:Ignorable="d" 
             TextElement.FontFamily="gogono_cocoa_mochi.ttf#Gogono Cocoa Mochi"
             d:DesignHeight="100" d:DesignWidth="100"
             x:Name="PROMPT_UC">
    <UserControl.Resources>
	
	<!-- A few StoryBoards here -->
	
        <Style TargetType="{x:Type TextBlock}"
             x:Key="PromptTextStyle">
            <Setter Property="FontSize" Value="26" />
            <Setter Property="ForeGround" Value="White" />
            <Setter Property="noesis:Text.Stroke" Value="Black" />
            <Setter Property="noesis:Text.StrokeThickness" Value="2.5" />
        </Style>

    </UserControl.Resources>

    <Grid x:Name="PROMPT_GRID">
        <TextBlock x:Name="PROMPT_TEXT" Text="" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="26" Visibility="Hidden" noesis:Text.Stroke="Black" noesis:Text.StrokeThickness="2.5" RenderTransformOrigin="0.5 0.5" >
            <TextBlock.RenderTransform>
                <TransformGroup x:Name="transformGroup">
                    <ScaleTransform/>
                </TransformGroup>
            </TextBlock.RenderTransform>

            <TextBlock.Foreground>
                <SolidColorBrush Color="Red"/>        
            </TextBlock.Foreground>
        </TextBlock>
        
        <TextBlock x:Name="SMALL_PROMPT_TEXT" Text="" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="26" Foreground="Red" Visibility="Hidden" noesis:Text.Stroke="Black" noesis:Text.StrokeThickness="2.5" RenderTransformOrigin="0.5 0.5">
            <TextBlock.RenderTransform>
                <TransformGroup x:Name="smallTransformGroup">
                    <ScaleTransform/>
                </TransformGroup>
            </TextBlock.RenderTransform>
        </TextBlock>
    </Grid>
</UserControl>
.Xaml Code where UserControl is put:
        <Viewbox Grid.Row="4" Grid.Column="4" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center">
            <uc:PromptGUI x:Name="PROMPT" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Viewbox>
c++ Code trying to switch color:
void PromptGUI::DisplayPrompt(const LambdaEngine::String& promptMessage, uint8 teamIndex)
{
	Noesis::SolidColorBrush* pBrush = new Noesis::SolidColorBrush();

	UNREFERENCED_VARIABLE(teamIndex);

	if (teamIndex != UINT8_MAX)
	{
		Noesis::Style* pStyle = FrameworkElement::FindResource<Noesis::Style>("PromptTextStyle");
		m_pPromptTextblock->SetStyle(pStyle);
	}
	else
	{
		pBrush->SetColor(Noesis::Color::Red());
		m_pPromptTextblock->SetForeground(pBrush);
	}

	m_pPromptTextblock->SetText(promptMessage.c_str());
	m_pPromptVisibilityStoryboard->Begin();
	m_pPromptStoryboard->Begin();
}
The problem that happens is that after the first color is set I can't change the color. so if this Usercontrol is invoked once with a red color, all other times I try to invoke this Prompt message it keeps the first color set. I tried to get the Textblock Brush and the brush foreGround color has changed but without any visual update. Another weird thing regarding this code is that if I try to use
Noesis::Ptr<Noesis::SolidColorBrush> pBrush = *new Noesis::SolidColorBrush()
instead of
Noesis::SolidColorBrush* pBrush = new Noesis::SolidColorBrush();
the application crashes. Using
Noesis::Ptr<Noesis::SolidColorBrush> pBrush = *new Noesis::SolidColorBrush()
when creating a new brush has never been an issue before until now and I can't understand why this should be a problem in this specific Case.

Bonus Questions:
Also we are using a NoesisGUI integrated in our Vulkan application and for some reason the application (SOMETIMES) crashes when
Noesis::Ptr<Noesis::IView>::Reset()
is called on the previous View and a new view is set and we can't figure out why this is.

And (SOMETIMES) when we try to set the rendertarget via SetRenderTarget the application crashes, again we have no idea what the issue might be as we are fairly certain our integration is correct.

Worth noting is that these "Bonus Questions"-crashes occur very rarely. If you guys have any idea what might cause these problems any tip would be much appreciated.

//The Toad

Re: Changing Color of Textblock Dynamically and a few other Q's.

Posted: 09 Dec 2020, 11:35
by TimTheToad
Your message disappeared :O But I managed to fix the color issue finally thanks to your help.

.xaml code:
    <Grid x:Name="PROMPT_GRID">
        <TextBlock x:Name="PROMPT_TEXT" Text="" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="26" Visibility="Hidden" noesis:Text.Stroke="Black" noesis:Text.StrokeThickness="2.5" RenderTransformOrigin="0.5 0.5" >
            <TextBlock.RenderTransform>
                <TransformGroup x:Name="transformGroup">
                    <ScaleTransform/>
                </TransformGroup>
            </TextBlock.RenderTransform>
            <TextBlock.Foreground>
                <SolidColorBrush Color="White"/>
            </TextBlock.Foreground>
        </TextBlock>
And in c++:
Noesis::SolidColorBrush* brush = (Noesis::SolidColorBrush*)m_pPromptTextblock->GetForeground();

	if (teamIndex != UINT8_MAX)
	{
		glm::vec3 color = TeamHelper::GetTeamColor(teamIndex);
		Noesis::Color teamColor = Noesis::Color(color.r, color.g, color.b);
		brush->SetColor(teamColor);
When I only defined the textcolor in .Xaml with i.e. ForeGround="Red" and I tried to get the foreground Noesis complained that this solidColorBrush was in a read-state only.
However, when I define the color using the example above (the one you recommended) it does not give me that log Error.

Anyway, thank you for your help! I will write another post regarding our other issues shortly :)

Cheers!

Re: Changing Color of Textblock Dynamically and a few other Q's.

Posted: 09 Dec 2020, 11:36
by sfernandez
Have you seen how we do that in our Scoreboard sample:
<DataTrigger Binding="{Binding Team}" Value="Alliance">
  <Setter TargetName="BackgroundBorder" Property="Background" Value="{StaticResource AllianceBg}"/>
  <Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="{StaticResource AllianceBd}"/>
  <Setter TargetName="PlayerName" Property="Foreground" Value="{StaticResource AllianceFg}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Team}" Value="Horde">
  <Setter TargetName="BackgroundBorder" Property="Background" Value="{StaticResource HordeBg}"/>
  <Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="{StaticResource HordeBd}"/>
  <Setter TargetName="PlayerName" Property="Foreground" Value="{StaticResource HordeFg}"/>
</DataTrigger>
We just use data triggers to determine which resources to apply to the text depending on the team value.

You can change those properties and launch the animations from xaml using interactivity triggers and actions, there is no need for code behind for that.

Re: Changing Color of Textblock Dynamically and a few other Q's.

Posted: 09 Dec 2020, 12:55
by sfernandez
Your message disappeared
Sorry about that, I was trying to provide a better solution and explanation for your problem.
When I only defined the textcolor in .Xaml with i.e. ForeGround="Red" and I tried to get the foreground Noesis complained that this solidColorBrush was in a read-state only.
However, when I define the color using the example above (the one you recommended) it does not give me that log Error.
When you specify Foreground="Red" in xaml the parser sets in the TextBlock a predefined brush that is frozen (in read-only state), it would be the same as setting Brushes::Red() in code.
On your last xaml the parser creates a new instance of a SolidColorBrush, so this will be a modifiable object, and that is why you can call SetColor() on that brush.
The problem that happens is that after the first color is set I can't change the color. so if this Usercontrol is invoked once with a red color, all other times I try to invoke this Prompt message it keeps the first color set. I tried to get the Textblock Brush and the brush foreGround color has changed but without any visual update.
Were you using animations on the TextBlock foreground? Or the problem was that you couldn't see the Foreground brush set in the style once you had the brush locally set?
As described here animation values have precedence over locally set values, and local values have precendence over style values, so that would explain it.

Re: Changing Color of Textblock Dynamically and a few other Q's.

Posted: 09 Dec 2020, 16:52
by jsantos
Another weird thing regarding this code is that if I try to use
Noesis::Ptr<Noesis::SolidColorBrush> pBrush = *new Noesis::SolidColorBrush()
instead of
Noesis::SolidColorBrush* pBrush = new Noesis::SolidColorBrush();
the application crashes.
Please, note that doing
Noesis::SolidColorBrush* pBrush = new Noesis::SolidColorBrush();
is going to generate a leak if you don't call Release later. We always recommend using Ptr to avoid this kind of potential errors. It is explained in the C++ Architecture Guide. We recommend careful reading of that guide and please let us know if something is not clear to improve the documentation.

We still need to understand why when using Ptr you were having a crash.

Re: Changing Color of Textblock Dynamically and a few other Q's.

Posted: 10 Dec 2020, 11:53
by TimTheToad
Another weird thing regarding this code is that if I try to use
Noesis::Ptr<Noesis::SolidColorBrush> pBrush = *new Noesis::SolidColorBrush()
instead of
Noesis::SolidColorBrush* pBrush = new Noesis::SolidColorBrush();
the application crashes.
We still need to understand why when using Ptr you were having a crash.
It crashed when setting the foreground (and using Ptr) on a Frozen Foreground. so now, when handling the foreground as sfernandez recommended it no longer crashes.
I'm not sure why it crashed but I suppose that's the issue.
Anyway, we always use Ptr when creating elements dynamically otherwise but as it didn't crash when using
Noesis::SolidColorBrush* pBrush = new Noesis::SolidColorBrush();
I felt like I had to ask you guys.

Re: Changing Color of Textblock Dynamically and a few other Q's.

Posted: 11 Dec 2020, 12:51
by sfernandez
I'm not able to reproduce the crash, are you still able to go back to a code that crashes?
How were you creating the Ptr from the Frozen foreground brush?