我正在制作Winforms程序,使用类似MVVM的模式。我的所有数据都连接到SessionModel
,传递给所有ViewModels
(我知道这可能不是最好的做事方式,但这就是我得到的)。
我的问题是:在ViewModel
内部我有一个事件监听器,它将事件连接到方法,如下所示:
// Base constructor
public MyViewModel(SessionModel session)
{
this.session = session;
MyUserControl.MyEvent_OnActivate += AddItem;
}
// This method should be called, whenever the event is invoked
private void AddItem()
{
session.Items.AddItem();
}
每次显示相应的View
时,都会生成ViewModel的新实例。这就产生了我的问题。因为一切都很好第一次我加载了View
和ViewModel
。但是第二次我访问它时,第一个实例仍然存在(虽然没有在任何地方引用),因此也接收了事件。结果是方法AddItem()
被称为两次(一次来自ViewModel
的每个实例。如果我再次导航到View
,它将是三次打电话,等等。
我的View
和ViewModel
是从MainForm
加载的,如下所示:
// When called, this method loads the view and view model
private void ShowMyView()
{
MyViewModel viewModel = new MyViewModel(session);
MyView view = new MyView(viewModel);
ShowContent(view);
}
// Clears content panel and shows new view
private void ShowContent(UserControl view)
{
while (pnlContent.Controls.Count > 0)
{
pnlContent.Controls[0].Dispose();
}
pnlContent.Controls.Add(view);
}
是否有一些清除视图模型旧实例的聪明方法,因为垃圾收集显然不够快?
答案 0 :(得分:0)
虽然没有在任何地方引用......
事件订阅确实可以引用订阅者。无论何时初始化新视图模型,旧视图模型都应取消订阅MyUserControl.MyEvent_OnActivate
。使ViewModel处于一次性状态,并使用Dispose
方法执行清理。
答案 1 :(得分:0)
我找到了一个解决方案,删除了event
并直接聆听delegate
,如this post中所述。
然后代码如下:
public class MyUserControl
{
internal delegate void MyDelegate();
(...)
}
public class MyViewModel
{
public MyVieWModel(SessionModel session)
{
this.session = session;
MyUserControl.MyDelegate = AddItem;
}
public void AddItem()
{
(...)
}
}
答案 2 :(得分:0)
MyControl
仍然保留对先前视图模型的引用的问题。
Winforms完全适合MVVM模式。它支持data-binding
(不像WPF那么强大)
我知道我正在扼杀MVVM,就像我一样使用它。它 是一个解决方案,因为我的观点包含用户控件,我有 到"跟"视图模型,他们不知道
通过在viewmodel中引用视图控件,可以打破MVVM模式。如果你继续"关注" MVVM - 你是独立的,不同类型的问题开始聚集,几周后你决定MVVM模式不可行;)
对于您的特定情况的简单建议,在不了解应用程序上下文的情况下,用户控制现在应该关注它所影响的视图模型。
您可以将视图模型的集合绑定到用户控件,只需在其中调用它的方法
private UserControl_OnActivate()
{
foreach (var viewmodel in ViewModels)
{
viewmodel.AddItem()
}
}
现在用户控件知道viewmodel和viewmodel对用户控件(视图)一无所知 - MVVM模式。
当您使用新的ViewModels
集合更新时,旧的viewmodel引用将被垃圾收集。