How to force IPropertyTypeCustomization to redraw

Hi,

is there a way to force the Customization class to redraw?

In the CustomizeChildren() function I decide to draw only specific elements of my UStruct, dependend on another value in the struct (so UI gets cleaned up for properties which anyway won’t be used).

CustomizeHeader(…)

TypeHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(SharedThis(this), &FStructCustomization::OnValueChanged));

CustomizeChildren(…):

if (ValueIsAllowed(type, propertyName, &customPropName) == true)
{
	IDetailPropertyRow &row = StructBuilder.AddChildProperty(ChildHandle.ToSharedRef());
	if (customPropName != "None")
		row.DisplayName(FText::FromName(customPropName));
}

Custom function:

void FStructCustomization::OnValueChanged()
{
	//force struct to update, so CustomizeChildren gets called again.???????
}

If the first of the properties get changed, I want that CustomizeChildren() gets called again, so the layout will be updated to the new visible values.

I guess this should not be impossible?
If yes, is there another way to update all content?

Assign the result of CustomizationUtils.GetPropertyUtilities() to a member variable of your customization class.
Then in OnValueChanged, called RequestRefresh() on that pointer. Pretty sure that should do it.

An alternative approach is to just use delegates to provide dynamic visibility for different parts of your customization, so you don’t need to rebuild. That can get messy if you have a complex customization though.

Neat, unfortunately it doesn’t workd :(, I’ve found a simple example in CaptureTypeCustomization.cpp.
This class is doing this:

void FCaptureTypeCustomization::OnPropertyChanged(TSharedPtr<FCaptureProtocolType> CaptureType, ESelectInfo::Type)
{
	SetCurrentIndex(CaptureType->ID.Identifier);
	PropertyHandle->SetValue(CaptureType->ID.Identifier);
	CurrentText->SetText(CaptureType->DisplayName);

	PropertyUtilities->RequestRefresh();
}

And I’m just doing this (as I just changed children of the struct, not the struct itself. This struct is normally inside of an TArray.

void FStructCustomization::CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
	StructPropertyHandle = InStructPropertyHandle;

	PropertyUtilities = StructCustomizationUtils.GetPropertyUtilities();

	uint32 NumChildren;
	StructPropertyHandle->GetNumChildren(NumChildren);
	FString label = "None";

	TypeHandle = StructPropertyHandle->GetChildHandle(TypeKey, false);
	if (TypeHandle.IsValid())
	{
		label = GetHandleName(TypeHandle, false);
		TypeHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(SharedThis(this), &FStructCustomization::OnValueChanged));
	}

	HeaderRow.NameContent()
		[
			StructPropertyHandle->CreatePropertyNameWidget(FText::FromString(label))
		];
}

void FStructCustomization::OnValueChanged()
{
	PropertyUtilities->RequestRefresh();
}

So I don’t have any properties to call SetValue(), and I guess therefore I doesn’t update.
Did I miss something?

Yeah.
OnValueChanged breakpoint is triggered. And after that no CustomizeHeader or CustomizeChildren breakpoint is triggered.

Yes in fact, I’m referencing a content browser asset in the Type variable. And when I change this asset pointer (by dragging or selecting from the dropdown) OnValueChanged is called.

I can’t see anything wrong with your code, and calling SetValue should not make any difference.

I assume you’re entering a new value for the ‘Type’ field of your struct and hitting return, and the label doesn’t update? Have you debugged and checked that, for example, OnValueChanged is being called.?

In that case I’m afraid I’m out of ideas, looks like it should work. I can only suggest trying to simplify your customization and seeing if you can get RequestRefresh to work at all, then if so work backwards to see why it doesn’t work in this case.

Hi kamrann,

as I debugged through all the ue4 code, I finally realized that customizeHeader and customizeChildren are only getting called on initialization anyway. So there can’t exist a way for a simple IPropertyCustomization to get these functions called again.

Although I found the class GameplayEffectModifierMagnitudeDetails.cpp in which delegate functions are used for visibility!

IDetailPropertyRow &row = StructBuilder.AddChildProperty(ChildHandle.ToSharedRef()); //add default property representation
row.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FActionCustomization::PropertyIsVisible, ChildHandle->GetProperty(), &row)));

Using this delegate function now works perfectly, as these delegate functions are called each update frame in UE4.

Thanks for the hints!

Instead of RequestRefresh, use ForceRefresh.

I have the same problem too, use ForceRefresh was right.