我有一个MainWindow.xaml
,DataContext
设置为MainWindowViewModel.cs
。在用户单击按钮并向窗口添加MyUserControl.xaml
之前,此窗口中没有任何内容。 MyUserControl.xaml
MyUserControlViewModel.cs
设置为DataContext
。
我想触发MyUserControlViewModel.cs
中被MainWindowViewModel.cs
捕获的事件。
到目前为止,我有这个。在我的MyUserControlViewModel.cs
public event EventHandler<LoadingEventArgs> LoadingEvent;
(...)
public void MyFunction() {
LoadingEvent(this, EventLibrary.LoadingEvent(2));
}
在我的MainWindowViewModel.cs
private MyUserControlViewModel _myUserControlViewModel;
public MyUserControlViewModel _MyUserControlViewModel {
get { return _myUserControlViewModel; }
private set { _myUserControlViewModel = value; OnPropertyChangedEvent("MyUserControlViewModel"); }
}
public MainWindowViewModel() {
// Can't attach event here
}
public void AddEventToUserControl() {
_MyUserControlViewModel = new MyUserControlViewModel();
_MyUserControlViewModel.LoadingEvent += MyUserControlViewModel_LoadingEvent;
}
private void MyUserControlViewModel_LoadingEvent(object sender, LoadingEventArgs e) {
MessageBox.Show("I got here!");
}
邮件"I got here"
从未显示,因为LoadingEvent
中的MyUserControlViewModel.cs
为null
。
我只在MyUserControlViewModel_LoadingEvent
函数之外附加MainWindowViewModel()
的原因是因为在加载窗口时不会添加MyUserControl.xaml
,而是在用户单击按钮后才会添加MyUserControlViewModel.cs
。 />
我认为这里的问题是事件不会与创建SonViewModel = new SonViewModel()
同时添加。
我需要知道如何通过代码动态创建通过ViewModel触发冒泡事件。
更新 - 更多信息已添加
鉴于我的上述情况可能很简单,缺乏重要细节,我将描述我的确切情况。
我有三种观点 - 祖父,父亲和儿子。对于每一个我有一个ViewModel类。在我的父亲中,我在XAML中声明了儿子,因为它是在同一时间创建的,所以当我FatherViewModel
中有SonViewModel
时,它指向正确的位置,我可以访问我需要的一切在SonViewModel
。因此,FatherViewModel
中正在被<View:SonView DataContext="{Binding SonViewModel, Mode=OneWay}" />
收听的任何事件都会被捕获
这里最重要的两个事实是父子俩都是同时创建的,儿子是在XAML中创建的,如下所示:
GrandfatherView.xaml
这很好,完全符合我的要求。
问题来自祖父和父亲,因为他们不是同时创造的。我首先创建GrandfatherView.cs
并在其中关联FatherView
(我知道它不是MVVM实践,但我试图在一个没有MVVM模式的项目中实现一些MVVM功能)我创建并添加了Grid
到FatherView _fatherView = new FatherView();
_fatherView.DataContext = new FatherViewModel();
mainGrid.Children.Add(_fatherView);
,如此:
FatherView
因为我在创建GrandfatherView
之后创建FatherViewModel
并通过代码添加它而没有特定的绑定,所以当我在{{1}中创建GrandfatherViewModel
对象时}},它没有指向我在我的应用程序中看到的FatherView
的实际ViewModel。
我不确定如何在代码中创建绑定<View:SonView DataContext="{Binding SonViewModel, Mode=OneWay}" />
,所以我可以确保属性和绑定是相同的,所以我GrandfatherViewModel
中的ViewModel对象实际上是我看到的那个在我的应用程序而不是一个全新的对象。
那么,有什么建议吗?
答案 0 :(得分:2)
问题的完整解决方案(使用Mvvm Light):
GrandFatherView.xaml
<Window x:Class="FunWithDynamicallyCreatedViewModels.GrandFatherView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Name="MainGrid" />
</Window>
GrandFatherView.xaml.cs
public sealed partial class GrandFatherView
{
public GrandFatherView()
{
InitializeComponent();
var fatherView = new FatherView
{
DataContext = new FatherViewModel
{
SonViewModel = new SonViewModel()
}
};
MainGrid.Children.Add(fatherView);
}
}
FatherView.xaml
<UserControl x:Class="FunWithDynamicallyCreatedViewModels.FatherView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:FunWithDynamicallyCreatedViewModels">
<local:SonView DataContext="{Binding SonViewModel}" />
</UserControl>
FatherViewModel.cs
public sealed class FatherViewModel : ViewModelBase
{
private SonViewModel _sonViewModel;
public SonViewModel SonViewModel
{
get { return _sonViewModel; }
set
{
if (SonViewModel != null)
SonViewModel.Event -= OnUserControlViewModelEvent;
Set(() => SonViewModel, ref _sonViewModel, value);
if (SonViewModel != null)
SonViewModel.Event += OnUserControlViewModelEvent;
}
}
private void OnUserControlViewModelEvent(object sender, EventArgs args)
{
// violation of MVVM for the sake of simplicity
MessageBox.Show("I got here!");
}
}
SonView.xaml
<UserControl x:Class="FunWithDynamicallyCreatedViewModels.SonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Command="{Binding InvokeEventCommand}"
Content="Invoke SonViewModel Event" />
</UserControl>
SonViewModel.cs
public sealed class SonViewModel
{
public SonViewModel()
{
InvokeEventCommand = new RelayCommand(() => Event(this, new EventArgs()));
}
public event EventHandler Event;
public ICommand InvokeEventCommand { get; private set; }
}