Caliburn.Micro嵌套了ViewModels的最佳实践
这是一个很长的问题,所以请耐心等待。
目前我正在开发一个小工具,旨在帮助我跟踪我的故事中无数的角色。
该工具执行以下操作:
这是我的问题:目前我在初始化ChracterViewModel时手动初始化子ViewModels。 但这对我来说听起来很可疑,我很确定有更好的方法可以做到这一点,但我看不出应该怎么做。
这是CharacterViewModel
的代码:
/// ViewModel for the character view. public class CharacterViewModel : Screen, IHandle<DataMessage> { // -------------------------------------------------------------------------------------------------------------------- // Fields // ------------------------------------------------------------------------------------------------------------------- /// The event aggregator. private readonly IEventAggregator eventAggregator; /// The character tags service. private ICharacterTagsService characterTagsService; // -------------------------------------------------------------------------------------------------------------------- // Constructors & Destructors // ------------------------------------------------------------------------------------------------------------------- /// Initializes a new instance of the class. public CharacterViewModel() { if (Execute.InDesignMode) { this.CharacterGeneralViewModel = new CharacterGeneralViewModel(); this.CharacterMetadataViewModel = new CharacterMetadataViewModel(); } } /// Initializes a new instance of the class. /// The event aggregator. [ImportingConstructor] public CharacterViewModel(IEventAggregator eventAggregator) : this() { this.eventAggregator = eventAggregator; this.eventAggregator.Subscribe(this); } // -------------------------------------------------------------------------------------------------------------------- // Properties // ------------------------------------------------------------------------------------------------------------------- /// Gets or sets the character. public Character Character { get; set; } /// Gets or sets the character general view model. public CharacterGeneralViewModel CharacterGeneralViewModel { get; set; } /// Gets or sets the character metadata view model. public CharacterMetadataViewModel CharacterMetadataViewModel { get; set; } /// Gets or sets the character characteristics view model. public CharacterApperanceViewModel CharacterCharacteristicsViewModel { get; set; } /// Gets or sets the character family view model. public CharacterFamilyViewModel CharacterFamilyViewModel { get; set; } // -------------------------------------------------------------------------------------------------------------------- // Methods // ------------------------------------------------------------------------------------------------------------------- /// Saves a character to the file system as a json file. public void SaveCharacter() { ICharacterSaveService saveService = new JsonCharacterSaveService(Constants.CharacterSavePathMyDocuments); saveService.SaveCharacter(this.Character); this.characterTagsService.AddTags(this.Character.Metadata.Tags); this.characterTagsService.SaveTags(); } /// Called when initializing. protected override void OnInitialize() { this.CharacterGeneralViewModel = new CharacterGeneralViewModel(this.eventAggregator); this.CharacterMetadataViewModel = new CharacterMetadataViewModel(this.eventAggregator, this.Character); this.CharacterCharacteristicsViewModel = new CharacterApperanceViewModel(this.eventAggregator, this.Character); this.CharacterFamilyViewModel = new CharacterFamilyViewModel(this.eventAggregator); this.eventAggregator.PublishOnUIThread(new CharacterMessage { Data = this.Character }); base.OnInitialize(); } /// /// Handles the message. /// /// The message. public void Handle(DataMessage message) { this.characterTagsService = message.Data; } }
对于完成清酒我也给你一个子ViewModels。 其他一个并不重要,因为它们的结构相同,只是执行不同的任务。
/// The character metadata view model. public class CharacterMetadataViewModel : Screen { /// The event aggregator. private readonly IEventAggregator eventAggregator; /// Initializes a new instance of the class. public CharacterMetadataViewModel() { if (Execute.InDesignMode) { this.Character = DesignData.LoadSampleCharacter(); } } /// Initializes a new instance of the class. /// The event aggregator. /// The character. public CharacterMetadataViewModel(IEventAggregator eventAggregator, Character character) { this.Character = character; this.eventAggregator = eventAggregator; this.eventAggregator.Subscribe(this); } /// Gets or sets the character. public Character Character { get; set; } /// /// Gets or sets the characters tags. /// public string Tags { get { return string.Join("; ", this.Character.Metadata.Tags); } set { char[] delimiters = { ',', ';', ' ' }; List tags = value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).ToList(); this.Character.Metadata.Tags = tags; this.NotifyOfPropertyChange(() => this.Tags); } } }
我已经阅读过Screens,Conductors and Composition , IResult和Coroutines , 并浏览了其余的文档,但不知怎的,我找不到我要找的东西。
//编辑:我应该提一下我工作的代码就好了。 我只是对它不满意,因为我认为我不太了解MVVM的概念,因此会产生错误的代码。
让一个ViewModel实例化几个子ViewModel没有任何问题。 如果您正在构建更大或更复杂的应用程序,那么如果您希望保持代码的可读性和可维护性,则几乎是不可避免的。
在您的示例中,每当您创建CharacterViewModel
实例时,都要实例化所有四个子ViewModel。 每个子ViewModels都将IEventAggregator
作为依赖项。 我建议您将这四个子ViewModel视为主要CharacterViewModel
依赖项,并通过构造函数导入它们:
[ImportingConstructor] public CharacterViewModel(IEventAggregator eventAggregator, CharacterGeneralViewModel generalViewModel, CharacterMetadataViewModel metadataViewModel, CharacterAppearanceViewModel appearanceViewModel, CharacterFamilyViewModel familyViewModel) { this.eventAggregator = eventAggregator; this.CharacterGeneralViewModel generalViewModel; this.CharacterMetadataViewModel = metadataViewModel; this.CharacterCharacteristicsViewModel = apperanceViewModel; this.CharacterFamilyViewModel = familyViewModel; this.eventAggregator.Subscribe(this); }
因此,您可以将子ViewModel属性的setter设为私有。
更改您的子ViewModels以通过构造函数注入导入IEventAggregator
:
[ImportingConstructor] public CharacterGeneralViewModel(IEventAggregator eventAggregator) { this.eventAggregator = eventAggregator; }
在您的示例中,其中两个子ViewModel在其构造函数中传递了Character
数据的实例,这意味着依赖关系。 在这些情况下,我会给每个子ViewModel一个公共的Initialize()
方法,您可以在其中设置Character
数据并在那里激活事件聚合器订阅:
public Initialize(Character character) { this.Character = character; this.eventAggregator.Subscribe(this); }
然后在CharacterViewModel
OnInitialize()
方法中调用此方法:
protected override void OnInitialize() { this.CharacterMetadataViewModel.Initialize(this.Character); this.CharacterCharacteristicsViewModel.Initialize(this.Character); this.eventAggregator.PublishOnUIThread(new CharacterMessage { Data = this.Character }); base.OnInitialize(); }
对于只通过EventAggregator
更新Character
数据的子ViewModel,请在构造函数中保留this.eventAggregator.Subscribe(this)
调用。
如果页面无法实际运行任何子ViewModel,则可以通过属性导入初始化这些VM属性:
[Import] public CharacterGeneralViewModel CharacterGeneralViewModel { get; set; }
直到构造函数完成运行后才会发生属性导入。
我还建议通过构造函数注入处理ICharacterSaveService
的实例化,而不是每次保存数据时显式创建新实例。
MVVM的主要目的是允许前端设计人员在可视化工具(Expression Blend)和编码器中处理UI的布局,以实现行为和业务,而不会相互干扰。 ViewModel公开要绑定到视图的数据,描述视图在抽象级别的行为,并经常充当后端服务的中介。
没有一种“正确”的方法可以做到这一点,并且有些情况下它不是最好的解决方案。 有时最好的解决方案是使用ViewModel抛出额外的抽象层,然后编写一些代码隐藏。 因此,虽然它对于整个应用程序来说是一个很好的结构,但是不要陷入强迫一切适合MVVM模式的陷阱。 如果你有一些图形复杂的用户控件,它只是更好地有一些代码隐藏,那么这就是你应该做的。
上述就是C#学习教程:Caliburn.Micro嵌套了ViewModels的最佳实践分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1006354.html