Overriding Serialize() does not work for WIDGETS

I have a class with some WITH_EDITOR code, that computes various things, and then changes the values in some UPROPERTY fields
Its worth mentioning that the UPROPERTYs in question are a TArray<uint8>, and a TArray<FSmallStruct>
(When this is all working they WONT be exposed to editor or blueprints - I just want the data serialized with the instances.)

Anyway, the code in the editor works, and the properties are changed in the BP instance, you can see them, the array is populated.
Then, as soon as I click the compile button, all the changes are reverted back to default values.

HOWEVER - If i make the property EditableAnywhere, let the editor code run to populate it, and then MANUALLY use the details panel to add an extra array item to the end… it all saves fine.

So, I’m guessing I need to tell unreal in my C++ code that I updated the tarray property, so it knows to serialize it, but I cant find a suitable .MarkDirty() .FlagForUpdate() or anything like that function to call to do it…

Alternatively, I have wondered if i need to call manually PostEditChangeChainProperty (because its an array), but if that is the way, I have no idea how I would create/fill out the parameters required to do that. (The parameters for FEditPropertyChain are hardly ‘intuitive’ to say the least)

Is anyone able to point me in the right direction please?

[BUMP]
Having scoured the internet, and posted on various forums, I’m getting literally nothing about this.
I can’t be the only person who wishes to modify TArray UPROPERTY values while IN THE EDITOR, using C++ code, and have the changes serialized as normal?

Did I miss the memo, showing a completely, fundamentally different way of going about this which everyone else is using?

I’m so close… everything else works fine, the values are just not serialized unless also manually messed with.(which isn’t a viable solution really)

[UPDATE]
Ok, so the problem seems to be… WIDGETS.
I made 2 test classes, one AActor, and one UUserWidget.
With (almost) identical code, overriding the Serialize() method, to save additional NON UPROPERTY field values.
With both classes I added a UFUNCTION(CallInEditor) which changes those field values, and calls the Modify() method to signify that changes have been made.

With the actor, this works entirely as expected, the values are changed, and the level the actor is placed in gets the star(*) indicating it has unsaved changes. Saving and running the level shows the altered values were indeed persisted. As does reloading the editor.
Everything is fine.

With the Widget this is NOT the case. Calling Modify() seems to do nothing. It certainly does not set the widget blueprint with the star(*), and manually saving does NOT serialize the altered values (in fact it seems to reset them to defaults BEFORE serialization even happens)

If I override the Modify() method and add this:

UObject* WidgetBPObject         = bIsEditorWidgetPreview ? WidgetTree_->RootWidget->WidgetGeneratedBy.Get() : WidgetTree_->GetOuter();

		if (UUserWidgetBlueprint* WidgetBP = Cast<UUserWidgetBlueprint>(WidgetBPObject))
		{
			return WidgetBP->Modify(true);
		}
		else if (UUserWidget* UserWidget = Cast<UUserWidget>(WidgetBPObject))
		{
			return UserWidget->Modify(true);
		}

(Which is based on code I ‘lifted’ from some other class in the editor)
Then the WidgetBlueprint DOES get a star(*) indicating that it has unsaved changes…
BUT the values which were modified are still not serialized.

Leaving me with the following questions:

  • What is actually going on here?
  • Why does this work one way for AActors, and is not consistent with UWidgets?
  • How are we ‘supposed’ to modify UWidget values from code at edit time?

And just in case anyone interested wants to see the code making the changes and serializing the values, here are the (most pertinent) chunks of the C++
(Note, this is taken from the AActor class, which works as expected. But the code is basically the same in the UWidget/UUserWidget class):

// Header 
class TESTIT_API ATestActor : public AActor
{
public:
	ATestActor();

	UPROPERTY(EditAnywhere, Category="Testing")
	FString SomeText;

	int32 ANumber = 0;

	FString AnotherString = TEXT("Default String Value");

	TArray<uint8> AnArray = {1, 2, 3, 4, 5, 6, 7, 8};

	virtual void Serialize(FArchive& Ar) override;

#if WITH_EDITOR

public:
	UFUNCTION(CallInEditor, Category="Testing")
	void Process();
	
#endif
};

// CPP File

void ATestActor::Serialize(FArchive& Ar)
{
	Super::Serialize(Ar);

	Ar << ANumber;
	Ar << AnotherString;
	Ar << AnArray;
}

void ATestActor::Process()
{
	Modify();
	ANumber       = 2345;
	AnotherString = TEXT("XXXXXXXXX");
	AnArray.Empty();
	for (uint8 i = 100; i < 110; ++i)
	{
		AnArray.Add(i);
	}
}

I’m wondering if the problem might be related to:
Issue UE-185003

Widget defaults not updated when modified on a base widget class via the hierarchy

The problem is that I just cannot find ANY single source which details using Serialize() and Modify() in respect to widgets.

If anyone reading this knows of any resource… come on, don’t be shy, help a dev out!