3

我希望你们能帮助我,因为我找不到任何有助于理解我的问题的有用信息:

我试图在我的 C# WinForms 应用程序上实现一种被动 MVP 方法,该应用程序具有列表视图和相应的详细视图。

到目前为止,我有以下结构(伪代码):

ListPresenter(new Repository(), new ListView(), new DetailPresenter(new DetailView());

执行:

public class UserDetailPresenter : IPresenter<IUserDetailView> 
{
    private IDetailView _view;
    public UserDetailPresenter(IDetailView detailView)
    {
        _view = detailView;
    }
    public void Show(IUser user) 
    { 
        InitializeView(user);
        _view.Show();
    }
}

public class UserListPresenter 
{
    //private members (_userRepo, _listView, _detailPresenter)        

    public UserListView(IUserRepository userRepo, IListView listView, IDetailPresenter detailPresenter) 
    {
        //wire up private members..
        _listView.EditCommandFired += this.ShowEditForm;
    }

    private void OnListViewEditCommandFired(object sender, EventArgs args)
    {
        _detailPresenter.LoadUser(_listView.SelectedUser);
        _detailPresenter.Show(); //modal
    }
}

public class UserListForm : Form, IUserListView
{
    public event EventHandler EditCommandFired;

    public IUser SelectedUser { get { return gridView.FocusedRowHandle as IUser; } }

    public void LoadUsers(List<IUser> users) 
    {
        gridView.DataSource = users;
    }

    // other UI stuff
}

我的问题是:我只能显示一次编辑表单。当我第二次尝试打开它时,我的视图(表单)被释放(System.ObjectDisposedException)。

我该如何解决?我在这里有错误的方法吗?我是否取消表单的关闭并隐藏它并信任垃圾收集器在处理后收集它DetailPresenter?每次Edit触发事件时,我是否创建(new() up)一个新的演示者?然后我将不得不引入某种工厂,因为我不知何故失去了依赖注入。如果有人能指出这种情况下的最佳实践是什么样的以及我在这里可能做错了什么,我会很感激。

4

2 回答 2

0

您正在使用一个实例DetailPresenter来显示不同对象的详细信息。DetailPresenter因此,在当前的实现中,每次要显示它时,您都必须初始化视图。这可能是一种方法,每次它要求显示它时ListPresenter都可以注入一个。new instanceDetailsViewDetailPresenter

public class UserDetailPresenter : IPresenter<IUserDetailView> 
{
    private IDetailView _view;
    public UserDetailPresenter()
    {

    }
    public void Show(IUser user, IDetailView detailView) 
        { 
            _view = detailView;
            InitializeView(user);
            _view.Show();
        }
}

或者另一种更简洁的方式可能是ViewFactory在显示视图之前获取视图的新实例。

private IDetailViewFactory _detailViewFactory;
    public UserDetailPresenter(IDetailViewFactory detailViewFactory)
    {
        _detailViewFactory = detailViewFactory;
    }
public void Show(IUser user ) 
        { 
            _view = _detailViewFactory.Resolve();//Some method to get a new view
            InitializeView(user);
            _view.Show();
        }

但如果你想做得有点不同,这是更多的passive view方式。在ListPresenter

private void OnListViewEditCommandFired(object sender, EventArgs args)
    {
        _listView.Show(_listView.SelectedUser);//tells view to show another view
    }

ListView

public ListView()
{
  new ListPresenter(this); // initializes presenter
}
public void Show(IUser user) 
{ 
  new DetailsView(user); // creates a new view
}

DetailsView

public DetailsView(IUser user)
{
  new DetailsPresenter(this, user); //creates presenter
}

最后:

public class UserDetailPresenter : IPresenter<IUserDetailView> 
{
    private IDetailView _view;
    public UserDetailPresenter(IDetailView detailView, IUser user)
    {
        _view = detailView;
         LoadUser(user);
         _view.SomeProperty = _userData;//to populate view with data
        _view.Show(); // tells the view to show data
    }
}
于 2014-01-04T01:19:52.930 回答
0

不久前我在做 Winforms MVP,所以不确定我是否可以提供帮助,但我的情况如下。在我的方法中,视图拥有演示者伪代码:

MyForm form = new MyForm(new PresenterX);
form.Show(); //or showdialog  

在这种情况下,关闭后实例仍然存在。

在您的情况下,由于演示者拥有视图,因此一旦不使用演示者,GC 可能会处理演示者和包含的视图。或者即使演示者仍在使用中,由于视图是私有的 GC 可能会在关闭后收集它。

尝试在发布模式下调试,看看关闭表单实例会发生什么。

编辑:

其他想法是:首先创建视图实例,然后传递给演示者

所以可能会失败的方法(我没有看到完整的代码所以猜测)

UserDetailPresenter p = new UserDetailPresenter(new YourView());

尝试

YourForm view = new YourForm(); //as global variable, view should be reusable anyway

代码中的某处

UserDetailPresenter p = new UserDetailPresenter(view);
p.Show(userInstance);
于 2014-01-03T22:41:39.897 回答