Binding delegates in a user widget.

So i been working on a inventory system and it was coming along great.
Drag and Drop is working and life was looking up.

Then i discoverd that my delegates is making my editor / game crash.
So am wondering where is it best to bind delegates located in the player controller?
is my class for it.


class MY_API UInventoryUserWidget : public UUserWidget
{
	GENERATED_UCLASS_BODY()
public:

	/*
		UUserWidget::
			Overriden methods.
	**/

	// Overriden to binds delegates on the AMyPlayerController:: at runtime (to avoid PC not present.)
	virtual void Construct_Implementation() override;

	/*
		UInventoryUserWidget ::
			Class methods.
	**/

	UFUNCTION()
		void CallPlayerPickupItem(FItemInventoryStruct NewItemToInventory);

	// Called when the delegate AMyPlayerController::OnPlayerStopLookingAtItemPickup is executed.
	UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "Notifie Player Picksup Item"))
		virtual void OnPlayerPickedItem(FItemInventoryStruct ItemThatWasPickedUp);

};

And is the implementation.


UInventoryUserWidget::UInventoryUserWidget(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{

}

void UInventoryUserWidget::Construct_Implementation()
{
	Super::Construct_Implementation();

	AMyPlayerController* PC = CAST_TO_MY_PC(GetOwningPlayer());
	if (PC)
	{
		// Calls CallPlayerPickupItem() that in turn calls the "BlueprintImplementableEvent" on OnPlayerPickedItem()
		PC->OnPlayerPickupItem.AddDynamic(this, &UInventoryUserWidget::CallPlayerPickupItem);
	}
}

void UInventoryUserWidget::CallPlayerPickupItem(FItemInventoryStruct NewItemToInventory)
{
	OnPlayerPickedItem(NewItemToInventory);
}

This all works great until i have opend and closed my inventory widget, next time i open it again it crashes.
Removing the lines in void UInventoryUserWidget::Construct_Implementation() “solves” the crash but am then left with no delegates.
The reson for not doing this is the constructor is that am assuming that there is no Player Controller at the time of the constructor is called?

Thanks for any help.

The “Construct” event is called every time the widget is added to the viewport, not when it’s “constructed” so it’s binding your delegates again each time. Ideally you should bind when added to viewport and unbind when removed from viewport, but there’s no event called when the widget is removed, so you have to do it manually.

Ok but i do need the delegate to fire when its not on screen as well.
Or players will only get a new item when they have there inventory widget open.

What I have seen epic do for code examples is to remove then add, its always safe to remove, even if its not yet bound.

So

// Calls CallPlayerPickupItem() that in turn calls the “BlueprintImplementableEvent” on OnPlayerPickedItem()
PC->OnPlayerPickupItem.RemoveDynamic(this, &UInventoryUserWidget::CallPlayerPickupItem);
PC->OnPlayerPickupItem.AddDynamic(this, &UInventoryUserWidget::CallPlayerPickupItem);

So simple yet so briliant :smiley: thanks for the help that solved the issue.

I was having problems with umg widgets communication -I ended creating a Blueprint actor only for housing event dispatchers for my widgets-.

I think the issues could be due to binding / unbinding when creation / removing from viewport. Actually I thought the unbinding was automatically done ! It is when destroying an actor, right?

I got similar problem and I solve it by add a condition (Not OnPlayerPickupItem…IsBound()).

//if PC and if button is NOT bound before
	if (PC && !PC->OnPlayerPickupItem.IsBound())
	{
		// Calls CallPlayerPickupItem() that in turn calls the "BlueprintImplementableEvent" on OnPlayerPickedItem()
		PC->OnPlayerPickupItem.AddDynamic(this, &UInventoryUserWidget::CallPlayerPickupItem);
	}

you should use OnInitiaziled or NativeOnInitialized not construct or preconstruct since those happen in editor time and the docs says you should not bind there.

Notice there also exists AddUniqueDynamic