I am currently trying to get into WPF and MVVM, but I recently ran into a problem I don't know how to solve. I am new to this, so if something is not as it should be, please tell me.
我目前正在尝试进入WPF和MVVM,但我最近遇到了一个我不知道如何解决的问题。我是新手,所以如果不是应该的话,请告诉我。
I have a ParentView with its ParentViewModel. The ParentView holds two views SubViewA and SubViewB which both have their own ViewModels. This is my ParentView.xaml:
我有一个带有ParentViewModel的ParentView。 ParentView拥有两个视图SubViewA和SubViewB,它们都有自己的ViewModel。这是我的ParentView.xaml:
<local:ViewBase.DataContext>
<local:ParentViewModel x:Name="Model" />
</local:ViewBase.DataContext>
<Grid>
<local:SubViewA Visibility="{Binding ElementName=Model, Path=SubViewAVisibility}" />
<local:SubViewB Visibility="{Binding ElementName=Model, Path=SubViewBVisibility}" />
</Grid>
What I want to do: SubViewModelB has a property that is binded to SubViewB. I want to change that property when a certain event occurs in the ParentViewModel. I suppose this should be done by binding the property in SubViewModelB to a property in ParentViewModel, but I'm not really sure how? I tried something like the following in the ParentView.xaml:
我想做的事:SubViewModelB有一个绑定到SubViewB的属性。我想在ParentViewModel中发生某个事件时更改该属性。我想这应该通过将SubViewModelB中的属性绑定到ParentViewModel中的属性来完成,但我不确定如何?我在ParentView.xaml中尝试了类似下面的内容:
<local:SubViewB Visibility="{Binding ElementName=Model, Path=SubViewBVisibility}" SomeProperty="{Binding ElementName=Model, Path=WhatIWantThePropertyToBe}" />
but that got me nowhere. So how do I solve this? I know I could do it via messaging in the MVVM light toolkit, but that seems kind of inappropiate for what I am trying to do. Any suggestions?
但那让我无处可去。那么我该如何解决这个问题呢?我知道我可以通过MVVM轻量级工具包中的消息传递来实现,但这似乎与我想要做的事情不相称。有什么建议么?
Thanks
谢谢
2 个解决方案
#1
3
Sounds like a good solution to this the EventAggregator pattern. There are some great implementations out there such as that provided by Microsoft Prism or TinyMessenger (very lightweight)
听起来像EventAggregator模式的一个很好的解决方案。有一些很棒的实现,例如Microsoft Prism或TinyMessenger提供的(非常轻量级)
As a code example you would do something like this (using Prism, untested code)
作为一个代码示例,你会做这样的事情(使用Prism,未经测试的代码)
public class ParentViewModel
{
private IEventAggregator eventAggregator;
public ParentViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
}
public void PublishSomeEvent()
{
// When a condition occurs, publish an event any subscribers
// that may be listening
this.eventAggregator.GetEvent<SomeEvent>()
.Publish(new SomeEvent("Hello World!")));
}
}
public class SubViewModel
{
private IEventAggregator eventAggregator;
public SubViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<SomeEvent>.SomeEvent(OnSomeEventOccurred);
}
public void OnSomeEventOccurred(SomeEvent arg)
{
// This method called when ParentViewModel publishes the event
Console.WriteLine(arg.OptionalMessage);
}
}
You would need a separate declaration of the event. For instance, I use this
您需要单独声明该事件。例如,我使用它
public SomeEvent : CompositePresentationEvent<SomeEvent>
{
public SomeEvent(string optionalMessage)
{
this.optionalMessage = optionalMessage;
}
public string OptionalMessage { get { return optionalMessage; } }
}
#2
1
You would have instance of SubViewModel
in your ParentViewModel
right? If you do then you can simply catch the event in ParentViewModel
and manually change the particular property value of SubViewModel
.
您的ParentViewModel中有SubViewModel的实例吗?如果这样做,您只需在ParentViewModel中捕获事件并手动更改SubViewModel的特定属性值。
I am not sure whether this is the perfect way or not but this should do the work.
我不确定这是否是完美的方式,但这应该做的工作。
Another way could be to directly bind the property of SubView with property in ParentViewModel
另一种方法是直接使用ParentViewModel中的属性绑定SubView的属性
Try something like this
尝试这样的事情
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.ParentViewModelProperty}"
#1
3
Sounds like a good solution to this the EventAggregator pattern. There are some great implementations out there such as that provided by Microsoft Prism or TinyMessenger (very lightweight)
听起来像EventAggregator模式的一个很好的解决方案。有一些很棒的实现,例如Microsoft Prism或TinyMessenger提供的(非常轻量级)
As a code example you would do something like this (using Prism, untested code)
作为一个代码示例,你会做这样的事情(使用Prism,未经测试的代码)
public class ParentViewModel
{
private IEventAggregator eventAggregator;
public ParentViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
}
public void PublishSomeEvent()
{
// When a condition occurs, publish an event any subscribers
// that may be listening
this.eventAggregator.GetEvent<SomeEvent>()
.Publish(new SomeEvent("Hello World!")));
}
}
public class SubViewModel
{
private IEventAggregator eventAggregator;
public SubViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<SomeEvent>.SomeEvent(OnSomeEventOccurred);
}
public void OnSomeEventOccurred(SomeEvent arg)
{
// This method called when ParentViewModel publishes the event
Console.WriteLine(arg.OptionalMessage);
}
}
You would need a separate declaration of the event. For instance, I use this
您需要单独声明该事件。例如,我使用它
public SomeEvent : CompositePresentationEvent<SomeEvent>
{
public SomeEvent(string optionalMessage)
{
this.optionalMessage = optionalMessage;
}
public string OptionalMessage { get { return optionalMessage; } }
}
#2
1
You would have instance of SubViewModel
in your ParentViewModel
right? If you do then you can simply catch the event in ParentViewModel
and manually change the particular property value of SubViewModel
.
您的ParentViewModel中有SubViewModel的实例吗?如果这样做,您只需在ParentViewModel中捕获事件并手动更改SubViewModel的特定属性值。
I am not sure whether this is the perfect way or not but this should do the work.
我不确定这是否是完美的方式,但这应该做的工作。
Another way could be to directly bind the property of SubView with property in ParentViewModel
另一种方法是直接使用ParentViewModel中的属性绑定SubView的属性
Try something like this
尝试这样的事情
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.ParentViewModelProperty}"