这是一个很长的问题,请耐心等待。
目前,我正在开发一个小工具,旨在帮助我跟踪“故事”中的众多角色。
该工具执行以下操作:
Conductor<Screen>.Collection.OneActive
)将打开一个新的字符(CharacterViewModel
源自)Screen
。Character
获取即将通过要打开的汉字IEventAggregator
信息系统。CharacterViewModel
还具有其是子的ViewModels结合到各种子视图的各种属性。这是我的问题:当前,我在初始化时手动初始化子ViewModels ChracterViewModel
。但这对我来说听起来像是可疑的,我很确定有更好的方法可以做到这一点,但是我不知道应该怎么做。
这是的代码CharacterViewModel
:
/// <summary>ViewModel for the character view.</summary>
public class CharacterViewModel : Screen, IHandle<DataMessage<ICharacterTagsService>>
{
// --------------------------------------------------------------------------------------------------------------------
// Fields
// -------------------------------------------------------------------------------------------------------------------
/// <summary>The event aggregator.</summary>
private readonly IEventAggregator eventAggregator;
/// <summary>The character tags service.</summary>
private ICharacterTagsService characterTagsService;
// --------------------------------------------------------------------------------------------------------------------
// Constructors & Destructors
// -------------------------------------------------------------------------------------------------------------------
/// <summary>Initializes a new instance of the <see cref="CharacterViewModel"/> class.</summary>
public CharacterViewModel()
{
if (Execute.InDesignMode)
{
this.CharacterGeneralViewModel = new CharacterGeneralViewModel();
this.CharacterMetadataViewModel = new CharacterMetadataViewModel();
}
}
/// <summary>Initializes a new instance of the <see cref="CharacterViewModel"/> class.</summary>
/// <param name="eventAggregator">The event aggregator.</param>
[ImportingConstructor]
public CharacterViewModel(IEventAggregator eventAggregator)
: this()
{
this.eventAggregator = eventAggregator;
this.eventAggregator.Subscribe(this);
}
// --------------------------------------------------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------------------------------------------------
/// <summary>Gets or sets the character.</summary>
public Character Character { get; set; }
/// <summary>Gets or sets the character general view model.</summary>
public CharacterGeneralViewModel CharacterGeneralViewModel { get; set; }
/// <summary>Gets or sets the character metadata view model.</summary>
public CharacterMetadataViewModel CharacterMetadataViewModel { get; set; }
/// <summary>Gets or sets the character characteristics view model.</summary>
public CharacterApperanceViewModel CharacterCharacteristicsViewModel { get; set; }
/// <summary>Gets or sets the character family view model.</summary>
public CharacterFamilyViewModel CharacterFamilyViewModel { get; set; }
// --------------------------------------------------------------------------------------------------------------------
// Methods
// -------------------------------------------------------------------------------------------------------------------
/// <summary>Saves a character to the file system as a json file.</summary>
public void SaveCharacter()
{
ICharacterSaveService saveService = new JsonCharacterSaveService(Constants.CharacterSavePathMyDocuments);
saveService.SaveCharacter(this.Character);
this.characterTagsService.AddTags(this.Character.Metadata.Tags);
this.characterTagsService.SaveTags();
}
/// <summary>Called when initializing.</summary>
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();
}
/// <summary>
/// Handles the message.
/// </summary>
/// <param name="message">The message.</param>
public void Handle(DataMessage<ICharacterTagsService> message)
{
this.characterTagsService = message.Data;
}
}
对于清酒,我还为您提供了一个子ViewModels。其他的一个并不重要,因为它们的结构相同,只是执行不同的任务。
/// <summary>The character metadata view model.</summary>
public class CharacterMetadataViewModel : Screen
{
/// <summary>The event aggregator.</summary>
private readonly IEventAggregator eventAggregator;
/// <summary>Initializes a new instance of the <see cref="CharacterMetadataViewModel"/> class.</summary>
public CharacterMetadataViewModel()
{
if (Execute.InDesignMode)
{
this.Character = DesignData.LoadSampleCharacter();
}
}
/// <summary>Initializes a new instance of the <see cref="CharacterMetadataViewModel"/> class.</summary>
/// <param name="eventAggregator">The event aggregator.</param>
/// <param name="character">The character.</param>
public CharacterMetadataViewModel(IEventAggregator eventAggregator, Character character)
{
this.Character = character;
this.eventAggregator = eventAggregator;
this.eventAggregator.Subscribe(this);
}
/// <summary>Gets or sets the character.</summary>
public Character Character { get; set; }
/// <summary>
/// Gets or sets the characters tags.
/// </summary>
public string Tags
{
get
{
return string.Join("; ", this.Character.Metadata.Tags);
}
set
{
char[] delimiters = { ',', ';', ' ' };
List<string> tags = value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).ToList();
this.Character.Metadata.Tags = tags;
this.NotifyOfPropertyChange(() => this.Tags);
}
}
}
我已经读过《屏幕,导体和成分》,《IResult》和《协程》,并浏览了其余的文档,但是不知何故找不到所需的内容。
// edit:我应该提到我的代码可以正常工作。我只是对它不满意,因为我认为我不太了解MVVM的概念,因此编写了错误的代码。
一个ViewModel实例化多个子ViewModel并没有错。如果要构建更大或更复杂的应用程序,则要保持代码的可读性和可维护性,这是不可避免的。
在您的示例中,每当创建的实例时,您都将实例化所有四个子ViewModel CharacterViewModel
。每个子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属性上的设置器设为私有。
更改您的子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();
}
对于仅Character
通过来更新数据的子ViewModels EventAggregator
,将this.eventAggregator.Subscribe(this)
调用保留在构造函数中。
如果页面正常运行实际上不需要您的任何子ViewModel,则可以通过属性导入来初始化这些VM属性:
[Import]
public CharacterGeneralViewModel CharacterGeneralViewModel { get; set; }
在构造函数完成运行之前,不会进行属性导入。
我还建议您也处理ICharacterSaveService
通过构造函数注入的实例化,而不是每次保存数据时都显式创建一个新实例。
MVVM的主要目的是允许前端设计人员使用可视化工具(Expression Blend)来处理UI的布局,并允许编码人员在不相互干扰的情况下实现行为和业务。ViewModel公开要绑定到视图的数据,以抽象级别描述视图的行为,并经常充当后端服务的中介。
没有一种“正确”的方法可以做到这一点,并且在某些情况下它不是最佳解决方案。有时,最好的解决方案是扔掉使用ViewModel的额外抽象层,然后编写一些代码隐藏。因此,尽管它对于您的整个应用程序来说是一个很好的结构,但不要陷入强迫所有内容都适合MVVM模式的陷阱。如果您在图形上有一些复杂的用户控件,那么在其中隐藏一些代码会更好,那么这就是您应该做的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句