如何绑定到列表视图的 OnItemSelectionChanged

How to bind to OnItemSelectionChanged of a list view

本文关键字:列表 视图 OnItemSelectionChanged 何绑定 绑定      更新时间:2023-10-16

在虚幻引擎4中,我想将一个事件绑定到UListView::OnItemSelectionChanged.该事件FOnItemSelectionChanged需要一个NullableItemType,所以我将指向列表视图的列表条目类(我的自定义类派生自IUserObjectListEntry)的指针作为参数传递。

UCLASS()
class PROJECT_API UMyListViewEntry : public UUserWidget, public IUserObjectListEntry
{
GENERATED_BODY()
// Members and functions don't matter here.
};
UCLASS()
class PROJECT_API UMyUserWidget : public UUserWidget
{
GENERATED_BODY()
void NativeConstruct() final
{
MyList->OnItemSelectionChanged.AddDynamic(this, &UMyUserWidget::MyEventCallback);
}
void MyEventCallback(UMyListViewEntry* e)
{
// implementation details
}
private:
UPROPERTY(meta = (BindWidget))
UListView* MyList;
};

但是,AddDynamic()调用会导致错误

C2228:".__Internal_AddDynamic"的左侧必须在类/结构/联合中

所以我想,我要绑定的回调函数(MyEventCallback())的签名是错误的。

应该绑定到UListView::OnItemSelectionChanged的函数的正确签名是什么?

它不仅关乎回调的签名,还关乎如何添加回调。

选项 #1:使用 OnItemSelectionChanged 的返回值(回调将限制为 UObject)

UListView中,它的成员OnItemSelectionChanged是通过宏IMPLEMENT_TYPED_UMG_LIST实现的,它

virtual FOnItemSelectionChanged& OnItemSelectionChanged() const override { return OnItemSelectionChangedEvent; }

因此,若要向委托添加回调函数,请使用返回值:

UCLASS()
class PROJECT_API UMyUserWidget : public UUserWidget
{
GENERATED_BODY()
void NativeConstruct() final
{
auto event = MyList->OnItemSelectionChanged();
event.AddUObject(this, &UMyUserWidget::MyEventCallback);
}
void MyEventCallback(UObject* e)
{
// implementation details, cast e to UMyListViewEntry*
}
// ...
};

您仅限于将UObject*作为参数的回调(UListView是其基类的专用化,使用UObject作为条目类型)。

蓝图(BP_OnItemSelectionChanged)中可用的委托不能使用,因为它是私有的。

选项 #2:定义自定义委托

如果要在回调中直接使用自定义条目类型作为参数,则可以

  1. 实现您自己的列表视图或
  2. 派生自UListView并在virtual void OnSelectionChangedInternal(UObject* FirstSelectedItem)中调用自定义委托

虽然第一种方法类似于UListView实现,但第二种方法非常短,可能类似于BP_OnItemSelectionChanged

DECLARE_MULTICAST_DELEGATE_TwoParams(FOnMyListItemSelectionChanged, UMyListViewEntry*, bool);
UCLASS(meta = (EntryInterface = UserObjectListEntry, EntryClass = UMyListViewEntry))
class PROJECT_API UMyListView : public UListView
{
GENERATED_BODY()
public:
FOnMyListItemSelectionChanged OnMyListItemSelectionChanged;
private:
void OnSelectionChangedInternal(UObject* FirstSelectedItem) override
{
Super::OnSelectionChangedInternal(FirstSelectedItem);
auto entry = Cast<UMyListViewEntry>(FirstSelectedItem);
OnMyListItemSelectionChanged.Broadcast(entry, entry != nullptr);
}
};
UCLASS()
class PROJECT_API UMyUserWidget : public UUserWidget
{
GENERATED_BODY()
void NativeConstruct() final
{
MyList->OnMyListItemSelectionChanged.AddUObject(this, &UMyUserWidget::MyEventCallback);
}
void MyEventCallback(UMyListViewEntry* e, bool isSelected)
{
// implementation details
}
private:
UPROPERTY(meta = (BindWidget), meta = (EntryClass = UMyListViewEntry))
UMyListView* MyList;
};