C# 更改ViewModel中的选定选项卡并在ViewModel之间发送对象

C# 更改ViewModel中的选定选项卡并在ViewModel之间发送对象,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我有一个wpf桌面应用程序,有3个ViewModels。 我有一个ViewModel,其中包含一个tabhost和两个选项卡。我有两张标签。每个选项卡都有自己的ViewModel。 我遇到的问题是,在tab1中,我有一个带有搜索结果的列表视图和一个按钮。当我在该列表中选择一个项目并按下按钮时,我想更改选项卡并显示关于我在选项卡2中选择的项目的信息。 我已经搜索了一个解决方案,但它似乎包括在MainViewModel中创建所有ViewModel,并向所有子ViewModel提供MainViewMo

我有一个wpf桌面应用程序,有3个ViewModels。 我有一个ViewModel,其中包含一个tabhost和两个选项卡。我有两张标签。每个选项卡都有自己的ViewModel。
我遇到的问题是,在tab1中,我有一个带有搜索结果的列表视图和一个按钮。当我在该列表中选择一个项目并按下按钮时,我想更改选项卡并显示关于我在选项卡2中选择的项目的信息。
我已经搜索了一个解决方案,但它似乎包括在MainViewModel中创建所有ViewModel,并向所有子ViewModel提供MainViewModel的引用。
没有别的办法吗



编辑

我只是设法用添加到项目中的MVVM light解决了我的问题

通过将MainViewModel中的一个方法和其中的一个属性绑定到.xaml,我现在可以使用信息从tab1调用它,告诉它更改tab。 另外,通过在tab2中绑定一个方法,我现在可以以相同的方式从tab1发送一个项

这就是我在将MVVM light导入到项目中后解决此问题的方法。
在表1中

Messenger.Default.Send<string, tab2ViewModel>(--object to send to tab2--);
Messenger.Default.Send<int, MainViewModel>(--tab index--);
Messenger.Default.Send(--要发送到tab2--)的对象;
sender.Default.Send(--tab index--);
在主/tab2中

Messenger.Default.Register<int>(this, ChangeTab);
public void ChangeTab(int i)
{
   SelectedTabIndex = i; //Bound property in .xaml
}
Messenger.Default.Register(这个,ChangeTab);
公共无效更改选项卡(int i)
{
SelectedTabIndex=i;//在.xaml中绑定属性
}
它似乎是自动工作的


谢谢你的答复。我还将研究Prism是如何工作的,看看用它来代替MVVM灯光是否有任何好处(不过现在还没有)。

解决您问题的一个好办法是使用Prism的EventAggregator

此服务允许您从应用程序中的任何位置侦听和发布特定类型的事件,而无需将视图模型彼此绑定。对于MVVM和其他松散耦合的设计来说,这是一个非常好的解决方案。这很简单,而且很有魅力

您可以在此处找到文档: 有关Prism的更多信息,请参见:


这是一个具体的例子。假设您想从应用程序中的任何位置更改主窗口的标题。您将创建此事件:

public class TitleChangedEvent : CompositePresentationEvent<string>{}
公共类标题ChangedEvent:CompositePresentationEvent{}
然后,您将在MainWindowViewModel中使用此事件,如下所示:

eventAggregator.GetEvent<TitleChangedEvent.Suscribe(
(newTitle) =>
{
    this.WindowTitle = newTitle;
});
eventAggregator.GetEvent<TitleChangedEvent>().Publish("This is a new title!");
Messenger.Send<TitleChangedMessage>(this, new TitleChangedMessage("This is a new title!"));
eventAggregator.GetEvent
{
this.WindowTitle=newTitle;
});
最后,您可以从应用程序中的任何位置更新标题,如下所示:

eventAggregator.GetEvent<TitleChangedEvent.Suscribe(
(newTitle) =>
{
    this.WindowTitle = newTitle;
});
eventAggregator.GetEvent<TitleChangedEvent>().Publish("This is a new title!");
Messenger.Send<TitleChangedMessage>(this, new TitleChangedMessage("This is a new title!"));
eventAggregator.GetEvent().Publish(“这是一个新标题!”);
正如你所见,这很容易


微笑地使用MVVM Light,您将首先创建一条通知消息:

public class TitleChangedMessage : GenericMessage<string>{}
公共类标题ChangedMessage:GenericMessage{}
然后,您将在MainWindowViewModel中听到如下消息:

Messenger.Register<TitleChangedMessage>(this, 
(message) =>
{
    this.WindowTitle = message.Content;
}
Messenger.注册(此,
(信息)=>
{
this.WindowTitle=message.Content;
}
您将发送如下更新:

eventAggregator.GetEvent<TitleChangedEvent.Suscribe(
(newTitle) =>
{
    this.WindowTitle = newTitle;
});
eventAggregator.GetEvent<TitleChangedEvent>().Publish("This is a new title!");
Messenger.Send<TitleChangedMessage>(this, new TitleChangedMessage("This is a new title!"));
Messenger.Send(这是新标题changedmessage(“这是新标题!”);
这是MVVM轻松实现的方式:)


您还可以看看这个相关的问题:

您可以将tab2的DataContext属性绑定到tab1的SelectedItem吗?不,我至少不这么认为。因为它们也在单独的.xaml文件中。我不建议直接使用.NET类型发送消息,因为当它被广播时,由于其他视图模型可能会侦听这种类型,您的应用程序将很快被垃圾邮件发送,您将不得不进行可怕的处理。基于GenericMessage创建类型。另外,我认为你可以接受这个答案。我明白了,我不确定情况是否如此,因为我指定了一个特定的ViewModel,在本例中是MainViewModel等。我确实注意到我可以在VM中注册2个方法,并且这两个方法都可以通过1个send调用。这是一个很好的功能,我将利用。您确定在Send方法中指定MainViewModel不会将其限制在该类中吗?不使用.Net类型的问题(因为它们是广播的)在MVVM light消息中通过使用令牌来处理。这看起来有点整洁。在我写第一篇文章的时候,我刚刚开始关注MVVM。从我所学到的一点,我认为它的工作方式几乎与Prism相同。你知道其中的区别吗?使用棱镜而不是MVVM灯是否更好?根据我看到的代码,它们看起来真的很奇怪……我更新了我的答案。关于框架的选择,他们是不同的。MVVM Light更倾向于MVVM模式,而Prism更倾向于应用程序模块化。但最终,他们所做的几乎是一样的。我个人更喜欢Prism,因为它内置了对MEF(随.NET4.0提供的模块化框架)的支持。我想我会继续使用MVVM light,因为它们看起来非常相似,而且我已经实现了它。而且因为您认为它更倾向于MVVM模式:)