View Issue Details

IDProjectCategoryView StatusLast Update
0002915NoesisGUIC++ SDKpublic2024-03-27 12:33
Reporteranton.sodergren_pdx Assigned Tosfernandez  
PrioritynormalSeveritymajor 
Status resolvedResolutionfixed 
Product Version3.2.2 
Target Version3.2.4Fixed in Version3.2.4 
Summary0002915: Unloaded event not invoked for inlines added through code
Description

When a view is closed/destroyed, it is expected that the Unloaded event is called for all child elements of the view. However, this event is not called for Inline elements inside of a TextBlock, which can result in some cleanup code not being executed. Specifically, the event is not called on the inlines if they were added through code, but the event seems to be called as expected if the inlines were added in XAML.

The inlines were added to the TextBlock in this manner:

Noesis::InlineCollection& Inlines = *GetInlines();
const auto Run = Noesis::MakePtr<Noesis::Run>();
Run->SetText( Text );
Inlines.Add( Run );

Steps To Reproduce

These are not the exact steps for reproduction that we used, but this should reproduce the issue:

  1. Create a view containing a TextBlock
  2. Add some code behind that creates and adds some inline elements to the TextBlock
  3. Add an event listener that listens for the Unloaded event on the inline elements and that does something that can be observed
  4. Invoke some code that closes the view containing the TextBlock and verify whether the Unloaded event was called or not
PlatformAny

Activities

sfernandez

sfernandez

2023-12-05 11:26

manager   ~0009001

Last edited: 2023-12-05 11:26

When you say "invoke some code that closes the view" you mean destroying the IView, or just taking the TextBlock out of the UI tree?
Anyway, I'm not able to reproduce the issue in any of those cases. I am using the following xaml:

<UserControl x:Class="Testing.TestInlines"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBlock x:Name="txt" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50"/>
<Button x:Name="btn" Content="Button" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="20"/>
</Grid>
</UserControl>

And this code-behind:
struct TestInlines: public UserControl
{
TestInlines()
{
InitializeComponent();

    Button* btn = FindName<Button>("btn");
    btn->Click() += [this](BaseComponent*, const RoutedEventArgs&)
    {
        TextBlock* txt = FindName<TextBlock>("txt");
        InlineCollection& inlines = *txt->GetInlines();
        Ptr<Run> run = Noesis::MakePtr<Noesis::Run>();
        run->SetText("Hello World!");
        run->Unloaded() += [](BaseComponent*, const RoutedEventArgs&) { NS_LOG_INFO("Run Unloaded"); };
        inlines.Add(run);
    };
}

void InitializeComponent() { GUI::LoadComponent(this, "InlinesUnloaded.xaml"); }

NS_IMPLEMENT_INLINE_REFLECTION_(TestInlines, UserControl, "Testing.TestInlines")

};


Could you reproduce it for example in the Hello World sample included in our SDK?

anton.sodergren_pdx

anton.sodergren_pdx

2023-12-08 13:49

reporter   ~0009004

Just destroying the UI element and thus taking it out of the UI tree, not destroying the top-level IView. I'll see if I can do a repro you can easily test.

anton.sodergren_pdx

anton.sodergren_pdx

2023-12-08 13:51

reporter   ~0009005

I do agree that your provided code should repro the issue based on my conclusions and what I wrote in the ticket, so I'll have to take a closer look at this.

sfernandez

sfernandez

2024-01-22 12:07

manager   ~0009098

Did you find a way to reproduce this behavior?

anton.sodergren_pdx

anton.sodergren_pdx

2024-02-20 17:27

reporter   ~0009224

Last edited: 2024-02-20 17:28

Hi, sorry that it took so long for me to get back to you. I have now managed to reproduce the issue in a more isolated manner. Try this code and see if it reproduces it for you:

// .h
struct TestInlines: public UserControl
{
TestInlines();
static void OnRegisterUnloadedEventsChanged( Noesis::DependencyObject pSender, const Noesis::DependencyPropertyChangedEventArgs& EventArgs );
static const Noesis::DependencyProperty
_pRegisterUnloadedEventsProperty;
NS_DECLARE_REFLECTION( TestInlines, UserControl )
};

// .cpp
TestInlines::TestInlines()
{
Noesis::GUI::LoadComponent( this, "InlinesUnloaded.xaml" );
}

void TestInlines::OnRegisterUnloadedEventsChanged( Noesis::DependencyObject pSender, const Noesis::DependencyPropertyChangedEventArgs& EventArgs )
{
Noesis::TextBlock
txt = Noesis::DynamicCast<Noesis::TextBlock*>( pSender );
if ( !txt )
{
return;
}

InlineCollection& inlines = *txt->GetInlines();
Ptr<Run> run = Noesis::MakePtr<Noesis::Run>();
run->SetText("Hello World!");
run->Unloaded() += [](BaseComponent*, const RoutedEventArgs&) { NS_LOG_INFO("Run Unloaded"); };
inlines.Add(run);

}

NS_IMPLEMENT_REFLECTION( CFleetOrderControl, "Testing.TestInlines" )
{
Noesis::UIElementData* pData = NsMeta<Noesis::UIElementData>( Noesis::TypeOf<SelfClass>() );
pData->RegisterProperty<bool>( MessageBoxTextProperty, "RegisterUnloadedEvents", Noesis::PropertyMetadata::Create( false, &OnRegisterUnloadedEventsChanged ) );
}

The dependency property is not the main issue here, I just added it for testing purposes.

This XAML works fine:

<UserControl x:Class="Testing.TestInlines"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:test="clr-namespace:Testing">
<Grid>
<TextBlock x:Name="txt" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50" test:TestInlines.RegisterUnloadedEvents="True" />
</Grid>
</UserControl>

While this does not.
<UserControl x:Class="Testing.TestInlines"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:test="clr-namespace:Testing">
<Grid>
<Control>
<Control.Template>
<ControlTemplate>
<TextBlock x:Name="txt" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50" test:TestInlines.RegisterUnloadedEvents="True" />
</ControlTemplate>
</Control.Template>
</Control>
</Grid>
</UserControl>

So something seems to go wrong when the text block is inside of a control template. It doesn't have to be the direct child of the control template, but it seems like it needs to be directly in the control template's scope, and not eg. be wrapper in a user control that is inside of the control template.

anton.sodergren_pdx

anton.sodergren_pdx

2024-03-07 16:23

reporter   ~0009292

Hello, just wanted to check, has there been another attempt at reproducing this issue?

sfernandez

sfernandez

2024-03-08 17:28

manager   ~0009305

Here is a patch that fixes the issue with inlines not being Loaded/Unloaded when created inside a template (the changes are on TextBlock::OnPostInit() method).

Index: TextBlock.cpp

--- TextBlock.cpp (revision 13486)
+++ TextBlock.cpp (working copy)
@@ -498,6 +498,18 @@
if (mInlines != 0)
{
ConnectInlines();
+

  • if (IsConnectedToView())
  • {
  • IView* view = GetView();
  • int numInlines = mInlines->Count();
  • for (int i = 0; i < numInlines; ++i)
  • {
  • Inline* inline_ = mInlines->Get(i);
  • inline_->OnConnectToView(view);
  • inline_->OnConnectToViewChildren();
  • }
  • }
    }

    mTextFlags |= TextFlags_InitializeFinished;

If you are not building Noesis from code, I can generate a patched Noesis library for you to try, which version would you need?

anton.sodergren_pdx

anton.sodergren_pdx

2024-03-11 12:53

reporter   ~0009311

Thank you, I will try this out today! We are not building Noesis from source in our usual build setup, but I think I can apply the patch and build Noesis locally.

anton.sodergren_pdx

anton.sodergren_pdx

2024-03-11 14:18

reporter   ~0009313

Nice, it does appear to fix this issue indeed, thanks! :) I'm supposing this will also get into Noesis 3.2.4?

We also have some different issues related to inlines, I was hoping that this fix would fix that too, but it seems that's not the case unfortunately. We're getting a heap corruption when calling Clear() on a Noesis::InlineCollection in some cases (it's related to bindings that we are doing in those inlines). But we'll continue investigating that a bit separately and see if that is also a Noesis bug or if we're doing something wrong with it.

sfernandez

sfernandez

2024-03-27 12:33

manager   ~0009351

Yes, this will be included in the next 3.2.4 version.

Please open a new ticket regarding the heap corruption deleting inlines if you find it is a Noesis issue, thanks!

Issue History

Date Modified Username Field Change
2023-12-04 13:01 anton.sodergren_pdx New Issue
2023-12-04 13:01 anton.sodergren_pdx Tag Attached: C++
2023-12-05 10:16 jsantos Target Version => 3.2.3
2023-12-05 10:16 jsantos Assigned To => sfernandez
2023-12-05 10:16 jsantos Status new => assigned
2023-12-05 11:26 sfernandez Status assigned => feedback
2023-12-05 11:26 sfernandez Note Added: 0009001
2023-12-05 11:26 sfernandez Note Edited: 0009001
2023-12-08 13:49 anton.sodergren_pdx Note Added: 0009004
2023-12-08 13:49 anton.sodergren_pdx Status feedback => assigned
2023-12-08 13:51 anton.sodergren_pdx Note Added: 0009005
2024-01-22 11:47 sfernandez Target Version 3.2.3 => 3.2.4
2024-01-22 12:07 sfernandez Status assigned => feedback
2024-01-22 12:07 sfernandez Note Added: 0009098
2024-02-20 17:27 anton.sodergren_pdx Note Added: 0009224
2024-02-20 17:27 anton.sodergren_pdx Status feedback => assigned
2024-02-20 17:28 anton.sodergren_pdx Note Edited: 0009224
2024-03-07 16:23 anton.sodergren_pdx Note Added: 0009292
2024-03-08 17:28 sfernandez Note Added: 0009305
2024-03-08 17:29 sfernandez Status assigned => feedback
2024-03-11 12:53 anton.sodergren_pdx Note Added: 0009311
2024-03-11 12:53 anton.sodergren_pdx Status feedback => assigned
2024-03-11 14:18 anton.sodergren_pdx Note Added: 0009313
2024-03-27 12:31 sfernandez Status assigned => resolved
2024-03-27 12:31 sfernandez Resolution open => fixed
2024-03-27 12:31 sfernandez Fixed in Version => 3.2.4
2024-03-27 12:33 sfernandez Note Added: 0009351