Unreal UMG MVVM

2023-10-31 18:52
文章标签 mvvm unreal umg

本文主要是介绍Unreal UMG MVVM,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Unreal UMG MVVM

文章目录

  • Unreal UMG MVVM
    • 背景
    • M - VM - V
    • 扩展点
    • === Editortime ===
    • Viewmodels 编辑器界面
    • View Bindings 编辑器界面
    • 蓝图编译相关
    • === Runtime ===
    • 创建 ViewModel
    • ViewModel 更新

背景

  1. 先阅读文档和 quabqi 的 UOD 视频分享,目前网上唯一的资料
  2. 看眼成熟的巨硬方案 WPF MVVM
  3. 剩下的就硬扒代码

M - VM - V

  1. Model:原始数据
  2. ViewModel:视图所需数据
  3. View:控件蓝图 WBP

扩展点

三个 Extension,注意 MVVM 是一个插件,通过这种方式扩展 WBP

// editortime
class MODELVIEWVIEWMODELBLUEPRINT_API UMVVMWidgetBlueprintExtension_View : public UWidgetBlueprintExtension
// runtime
class MODELVIEWVIEWMODEL_API UMVVMView : public UUserWidgetExtension
class MODELVIEWVIEWMODEL_API UMVVMViewClass : public UWidgetBlueprintGeneratedClassExtension

新增一个 BP Compiler, MVVM 自动生成了一部分 BP 代码

FKismetCompilerContext::RegisterCompilerForBP(UMVVMViewModelBlueprint::StaticClass(), &UMVVMViewModelBlueprint::GetCompilerForViewModelBlueprint);

=== Editortime ===

有两个编辑器界面

在这里插入图片描述

WidgetBlueprint.UMVVMBlueprintView,这也是通过 WBP Extension UMVVMWidgetBlueprintExtension_View 挂上的

两个编辑器,一个添加 VM Class,一个添加 Binding,最终存储在 UMVVMBlueprintView

// UMVVMBlueprintView
UPROPERTY(EditAnywhere, Category = "MVVM")
TArray<FMVVMBlueprintViewBinding> Bindings;UPROPERTY(EditAnywhere, Category = "MVVM")
TArray<FMVVMBlueprintViewModelContext> AvailableViewModels;

Viewmodels 编辑器界面

在这里插入图片描述

// Editor AddViewModel
if (UWidgetBlueprint* WidgetBlueprint = WidgetBlueprintEditor->GetWidgetBlueprintObj())
{UMVVMEditorSubsystem* EditorSubsystem = GEditor->GetEditorSubsystem<UMVVMEditorSubsystem>();check(EditorSubsystem);UMVVMBlueprintView* CurrentBlueprintView = WeakBlueprintView.Get();if (!CurrentBlueprintView){CurrentBlueprintView = EditorSubsystem->RequestView(WidgetBlueprint);WeakBlueprintView = CurrentBlueprintView;ViewModelsUpdatedHandle = CurrentBlueprintView->OnViewModelsUpdated.AddSP(this, &SMVVMViewModelPanel::HandleViewModelsUpdated);}EditorSubsystem->AddViewModel(WidgetBlueprint, SelectedClass);
}

View Bindings 编辑器界面

在这里插入图片描述

蓝图编译相关

UMVVMBlueprintView 编辑时数据编译到 UMVVMViewClass 给运行时用

// FMVVMViewBlueprintCompiler::PreCompileBindingSources
UMVVMViewClass* ViewExtension = NewObject<UMVVMViewClass>(Class);
CurrentCompilerContext->Compile(Class, BlueprintView, ViewExtension);
CurrentCompilerContext->AddExtension(Class, ViewExtension);// FMVVMViewBlueprintCompiler::Compile
CompileSourceCreators(CompileResult.GetValue(), Class, BlueprintView, ViewExtension);
CompileBindings(CompileResult.GetValue(), Class, BlueprintView, ViewExtension);
ViewExtension->BindingLibrary = MoveTemp(CompileResult.GetValue().Library);

=== Runtime ===

创建 ViewModel

四种模式,134 都是自动创建并关联,以默认的 Create Instance 为例

视图模型创建类型描述
自动创建小部件会自动创建自己的 Viewmodel 实例。
手动创建小部件初始化时 Viewmodel 为 null,您需要手动创建一个实例并分配它。
全局视图模型集合指的是一个全局可用的视图模型,可以被项目中的任何小部件使用。需要全局视图模型标识符。
属性路径在初始化时,执行一个函数来查找 Viewmodel。Viewmodel 属性路径使用由句点分隔的成员名称。

Widget::Init -> Init Extensions -> MVVMViewClass -> MVVMView

在这里插入图片描述

UMVVMViewClass 每个 WBP Class 一份,是编辑时存下的绑定数据
MVVMView 每个 WBP Instance 一份
UMVVMViewClass 拉起每个 WBP Instance 的 MVVMView

void UMVVMViewClass::Initialize(UUserWidget* UserWidget)
{ensure(UserWidget->GetExtension<UMVVMView>() == nullptr);UMVVMView* View = UserWidget->AddExtension<UMVVMView>();if (ensure(View)){if (!bLoaded){BindingLibrary.Load();bLoaded = true;}View->ConstructView(this);}
}

CreateInstance,如前所说,会自动创建并关联 ViewModel 实例和 WBP 实例

/**
* Instance UMVVMClassExtension_View for the UUserWdiget
*/
UCLASS(Transient, DisplayName="MVVM View")
class MODELVIEWVIEWMODEL_API UMVVMView : public UUserWidgetExtensionvoid UMVVMView::Construct()
{// Init ViewModel instancesfor (const FMVVMViewClass_SourceCreator& Item : ClassExtension->GetViewModelCreators()){Item.CreateInstance(ClassExtension, this, GetUserWidget());}...
}UObject* FMVVMViewClass_SourceCreator::CreateInstance(const UMVVMViewClass* InViewClass, UMVVMView* InView, UUserWidget* InUserWidget) const
{UObject* Result = nullptr;FObjectPropertyBase* FoundObjectProperty = FindFProperty<FObjectPropertyBase>(InUserWidget->GetClass(), PropertyName);if (ensureAlwaysMsgf(FoundObjectProperty, TEXT("The compiler should have added the property"))){auto AssignProperty = [FoundObjectProperty, InUserWidget](UObject* NewObject){check(NewObject);if (ensure(NewObject->GetClass()->IsChildOf(FoundObjectProperty->PropertyClass))){FoundObjectProperty->SetObjectPropertyValue_InContainer(InUserWidget, NewObject);}};if (bCreateInstance){//...}else if (GlobalViewModelInstance.IsValid()){//...}else if (FieldPath.IsValid()){//...}}return Result;
}

ViewModel 更新

C++ 封装 SetXXX 函数来调用 UE_MVVM_SET_PROPERTY_VALUE 宏

/** After a field value changed. Broadcast the event. */
#define UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(MemberName) \BroadcastFieldValueChanged(ThisClass::FFieldNotificationClassDescriptor::MemberName)/** If the property value changed then set the new value and notify. */
#define UE_MVVM_SET_PROPERTY_VALUE(MemberName, NewValue) \SetPropertyValue(MemberName, NewValue, ThisClass::FFieldNotificationClassDescriptor::MemberName)/** Set the new value and notify if the property value changed. */
template<typename T, typename U>
bool SetPropertyValue(T& Value, const U& NewValue, UE::FieldNotification::FFieldId FieldId)
{if (Value == NewValue){return false;}Value = NewValue;BroadcastFieldValueChanged(FieldId);return true;
}

蓝图换掉 SetProperty 指令

DEFINE_FUNCTION(UMVVMViewModelBase::execK2_SetPropertyValue)
{UMVVMViewModelBase* ViewModelContext = Cast<UMVVMViewModelBase>(Context);bResult = TargetProperty->Identical(TargetValuePtr, SourceValuePtr);if (!bResult){// Set the value then notify that the value changed.TargetProperty->SetValue_InContainer(ViewModelContext, SourceValuePtr);ViewModelContext->BroadcastFieldValueChanged(FieldId);}
}

总之都是调用 BroadcastFieldValueChanged,ViewModel 派生了 INotifyFieldValueChanged 来监听属性变化

但是其实就是封装了 Setter,每次变了就调用下 Delegate 派发事件

class MODELVIEWVIEWMODEL_API UMVVMViewModelBase : public UObject, public INotifyFieldValueChangedvirtual FDelegateHandle AddFieldValueChangedDelegate(UE::FieldNotification::FFieldId InFieldId, FFieldValueChangedDelegate InNewDelegate) override final;void UMVVMViewModelBase::BroadcastFieldValueChanged(UE::FieldNotification::FFieldId InFieldId)
{NotificationDelegates.BroadcastFieldValueChanged(this, InFieldId);
}

蓝图编辑的 Binding 数据,会在 WBP::SetXXXViewModel 时解绑旧的,再绑新的

// 贴下入口函数,代码不贴了
UMVVMView::SetViewModel
UMVVMView::EnableLibraryBinding

这篇关于Unreal UMG MVVM的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/317412

相关文章

MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)

1、MVC MVC(Model-View-Controller) 是一种常用的架构模式,用于分离应用程序的逻辑、数据和展示。它通过三个核心组件(模型、视图和控制器)将应用程序的业务逻辑与用户界面隔离,促进代码的可维护性、可扩展性和模块化。在 MVC 模式中,各组件可以与多种设计模式结合使用,以增强灵活性和可维护性。以下是 MVC 各组件与常见设计模式的关系和作用: 1. Model(模型)

前端---对MVC MVP MVVM的理解

就需要从前端这些年的从无到有、从有到优的变迁过程讲一下。 1. Web1.0时代 在web1.0时代并没有前端的概念,开发一个web应用多数采用ASP.NET/Java/PHP编写,项目通常用多个aspx/jsp/php文件构成,每个文件中同时包含了HTML、CSS、JavaScript、c#/Java/PHP代码,系统整体架构可能是这样子的: 我们可以看到服务端是比较重的,有一块既在客户

MVVM到底是什么

MVVM到底是什么 文章目录 MVVM到底是什么一、MVVM是什么二、为什么这么定义1. 分离关注点2. 提高可维护性3. 数据绑定和事件驱动4. 支持前端框架的发展 三、底层逻辑1. ViewModel层2. 数据绑定3. 事件驱动4. 响应式系统 四、扩展与高级技巧1. 组件化开发2. 双向数据绑定3. 计算属性和侦听器4. 插槽

翻译Houdini官方对UE4新版插件的介绍:Houdini Engine for Unreal - V2

原视频:Houdini For Unreal - YouTube 目录 介绍0. 总览1. 简介HoudiniEngine2. UE4的HoudiniEngine - 第二版为什么要做“第二版” ?What's new? - 核心What's new? - 输出(1)What's new? - 输出(2)What's new? - 输入What's new? - 参数What's new?

一个同行的mvvm详细讲解

下面的地址是一个同行讲的mvvm,讲得非常详细,清晰,推荐! http://www.ios122.com/2015/10/mvvm_1/ http://www.cocoachina.com/ios/20160301/15425.html https://github.com/lovemo/MVVMFramework-Swift    代码示例!

【MVVM】Data Binding代码实践(告别findViewById)(四)

Data Binding实战(一)  Data Binding语法解析(二)  Data Binding高级用法(三)  好了,继前三篇学习了Data Binding之后,我们可以发现它的强大之处有这么几点: 1、使用MVVM模式,让整个项目结构清晰明了  2、通过ViewModel连接View和Model,使得View与Model层解耦,分层后各司其职,维护方便  3、易于项目的测试

【MVVM】Data Binding高级用法-Observable、动态生成Binding Class(三)

设置View的id 虽然说Data Binding这种分层模式使得我们对数据的传递简单明了,一般情况下我们可以不设置View的id,不使用findViewById即可对View进行数据上一系列的操作,不过有时候根据情况我们需要对某些View设置id,但是还是可以不findViewById即可得到该控件的对象,因为设置id后ViewDataBinding类会自动生成对应的控件对象,如: <c

【MVVM】 Android Data Binding语法解析(二)

上篇我们知道了Data Binding的最简单的用法,那么Data Binding其中最为重要也是最复杂的其实就是在xml布局文件中给对应的控件进行数据绑定了,接下来就一一说明Data Binding的使用各个场景的语法。 我们以User类这个Model为例: <code class="hljs java has-numbering" style="display: block; p

【MVVM】Android Data Binding实战(一)

在今年Google I/O大会上,Google推出Design Library库的同时也推出了Android Data Binding,那么什么是Data Binding?其名曰数据绑定,使用它我们可以轻松实现MVVM(模型-视图-视图模型)模式,来实现应用之间数据与视图的分离、视图与业务逻辑的分离、数据与业务逻辑的分离,从而达到低耦合、可重用性、易测试性等好处,那么我们首先先来看看什么是MV

MVVM 设计模式:构建高效且可维护的前端应用

在现代前端开发中,随着应用规模的不断扩大和复杂性的增加,采用合适的设计模式变得尤为重要。MVVM(Model-View-ViewModel)作为一种流行的设计模式,它通过分离业务逻辑和用户界面,提高了代码的可维护性和可测试性。本文将详细介绍MVVM的核心概念、优势以及如何在前端项目中实现MVVM。 什么是MVVM? MVVM是一种软件设计模式,用于组织和分离用户界面(UI)的各个部分。它由三个