在我的WPF MVVM应用程序中,使用Caliburn.Micro,我有一个ViewModel,CreateServiceViewModel
,在按钮单击时,在一个单独的窗口中打开一个GridView,供用户从中选择一行。
我为此创建了另一个ViewModel MemberSearchViewModel
,它有两个属性:
private Member selectedMember;
public Member SelectedMember
{
get { return selectedMember; }
set { selectedMember = value; }
}
private IList<Member> members;
public IList<Member> Members
{
get { return members; }
set { members = value; }
}
如何将SelectedMember值恢复为调用ViewModel? ViewModel的属性为Service.SelectedMember
。
答案 0 :(得分:2)
EventAggregator是您可以使用的......我相信很多解决方案之一。
public class MessageNotifier{
public object Content{get;set;}
public string Message {get;set;}
}
//MEF bits here
public class HelloWorldViewModel: Screen, IHandle<MessageNotifier>{
private readonly IEventAggregator _eventAggregator
//MEF constructor bits
public YourViewModel(IEventAggregator eventAggregator){
_eventAggregator = eventAggregator;
}
public override OnActivate(){
_eventAggregator.Subscribe(this);
}
public override OnDeactivate(){
_eventAggregator.UnSubscribe(this);
}
//I Handle all messages with this signature and if the message applies to me do something
//
public void Handle(MesssageNotifier _notifier){
if(_notifier.Message == "NewSelectedItem"){
//do something with the content of the selectedItem
var x = _notifier.Content
}
}
}
//MEF attrs
public class HelloWorld2ViewModel: Screen{
private readonly IEventAggregator _eventAggregator
//MEF attrs
public HelloWorld2ViewModel(IEventAggregator eventAggregator){
_eventAggregator = eventAggregator;
}
public someobject SelectedItem{
get{ return _someobject ;}
set{ _someobject = value;
NotifyOfPropertyChange(()=>SelectedItem);
_eventAggregator.Publish(new MessageNotifier(){ Content = SelectedItem, Message="NewSelectedItem"});
}
}
答案 1 :(得分:1)
一种选择是利用NotifyPropertyChanged
。由于您正在使用ViewModel,因此它们很可能实现INotifyPropertyChanged
,您可以像框架一样使用它。
当您的CreateServiceViewModel创建MemberSearchViewModel时,它只会订阅PropertyChanged事件:
//This goes wherever you create your child view model
var memberSearchViewModel = new MemberSearchViewModel(); //Or using a service locator, if applicable
memberSearchViewModel.PropertyChanged += OnMemberSearchPropertyChanged;
private void OnMemberSearchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "SelectedMember")
{
//Code to respond to a change in the Member
}
}
然后在您的MemberSearchViewModel中,只需在用户从网格中选择成员时引发NotifyPropertyChanged事件。
编辑:
正如@DNH在注释中正确注意到的那样,如果没有正确清理,使用这样的事件处理程序可能会导致内存泄漏。因此,当您完成MemberSearchViewModel时,请务必取消订阅PropertyChanged
事件。因此,例如,如果您只需要它直到用户选择一个成员,您可以将其放入Property Changed Handler本身(我已将其切换为使用类级变量来保存ViewModel):
private void OnMemberSearchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "SelectedMember")
{
//Code to respond to a change in the Member
//Unsubscribe so the view model can be garbage collected
_memberSearchViewModel.PropertyChanged -= OnMemberSearchPropertyChanged;
_memberSearchViewModel = null;
}
}
答案 2 :(得分:0)
一种选择是将MemberSearchViewModel
存储为CreateServiceViewModel
字段并定义CreateServiceViewModel.SelectedMember
属性,如下所示:
public Member SelectedMember
{
get
{
return _memberSearchViewModel.SelectedMember;
}
set
{
_memberSearchViewModel.SelectedMember = value;
}
}
答案 3 :(得分:0)
怎么样?
public interface INotifyMe<T>
{
T ResultToNotify { get; set; }
}
public class CreateServiceViewModel : ViewModelBase, INotifyMe<Member>
{
// implement the interface as you like...
}
public class MemberSearchViewModel : ViewModelBase
{
public MemberSearchViewModel(INotifyMe<Member> toBeNotified)
{
// initialize field and so on...
}
}
现在你可以让CreateServiceViewModel
监听它自己的属性,你不必考虑删除事件监听器。
当然要做更经典的方式,或者使用像这样的界面。
public interface INotifyMe<T>
{
void Notify(T result);
}
答案 4 :(得分:0)
作为评论的后续内容,以下是使用Prism
的示例 - 我从未使用Caliburn
。
创建活动 - 活动的有效负载将是您的SelectedMember:
public class YourEvent:CompositePresentationEvent<YourEventPayload>{}
发布活动:
EventAggregator.GetEvent<YourEvent>().Publish(YourEventPayload);
订阅活动:
EventAggregator.GetEvent<YourEvent>().Subscribe((i) => ...);