简体   繁体   中英

MVP pattern in winforms - Handling events

I just started with C# and MVP design pattern. I'm in doubt about concrete implementation when it comes to event handling. I'm aware of that, view shouldn't know about presenter and presenter should control a view through view interface.

Let's say I have 2 text boxes and would like to check for errors. If an error occurs I want to change text box Text property. Is it wrong approach to create one EventHandler and use sender object to verify witch text box is user currently using?

Something like:

IView:

interface IMainView
{
    event KeyPressEventHandler KeyPressed;
}

View:

public partial class MainView : Form, IMainView
{
    public frmInterakcija()
    {
        InitializeComponent();
        this.textBox1.Name = "textBox1";
        this.textBox2.Name = "textBox2";
        new MainPresenter();
        Bind();
    }

    private void Bind()
    {

       this.textBox1.KeyPress += KeyPressed;
       this.textBox2.KeyPress += KeyPressed;
    }
}

Presenter:

class MainPresenter
{
    private IMainView _view;

    public MainPresenter(IMainView view) 
    {
        _view = view;
        this.initialize();

    }

    public void initialize()
    {
        _view.KeyPressed += _view_textBoxKeyPressed;
    }

    public void _view_textBoxKeyPressed(object sender, EventArgs e)
    {
        if (sender.GetType() == typeof(TextBox))
        {
            TextBox textBox = (TextBox)sender;
            if (textBox.Name.Equals("textbox1") 
                {...} // Do validation/changes on textbox1
            else ...

        }
    }
 }

Or instead of this above I should create event handler for every textbox I have and update/handle errors through properties? (this will make my code redundant I guess)

What would be right approach?

IMHO the presenter should be unaware of view specific objects (example textbox in your code). That kind of logic should not be in presenter. And presenter must not know about the Ids of controls in the UI, that's even worse. Remember one of the benefits of this should be that you can test the presenter by mocking the view, if you have UI specific code you won't be able to unit test the presenter.

It does seem like two different events to me since you are doing different logic. I'd raise two different events and one would do validation, the other would do its own logic. The presenter won't have to check if the sender is textbox or the id of the textbox . Also what if you have another textbox, you'll need another if condition in this current implementation.

Also, in the view, it should be new MainPresenter(this);

Your presenter should absolutely not have view-specific types in it (eg controls, events, etc.) since these are hard to fake when it comes time to test the presenter's logic. Instead, you should have something like the following.

IView:

interface IMainView
{
    // give these better names based on what they actually represent (e.g. FirstName and LastName)
    // you could also add setters if you needed to modify their values from the presenter
    string Text1 { get; } 
    string Text2 { get; }

    // provide a way to bubble up validation errors to the UI
    string ErrorMessage { get; set; }
}

Presenter:

class MainPresenter
{
    private IMainView _view;

    public MainPresenter(IMainView view) 
    {
        _view = view;
    }

    public void ValidateText1()
    {
        if (/* some validation is false */)
        {
            _view.ErrorMessage = "Text1 isn't valid";
        }
    }

    public void ValidateText2()
    {
        if (/* some validation is false */)
        {
            _view.ErrorMessage = "Text2 isn't valid";
        }
    }
 }

View:

public partial class MainView : Form, IMainView
{
    var readonly MainPresenter _presenter;

    public frmInterakcija()
    {
        InitializeComponent();
        _presenter = new MainPresenter(this);
    }

    private void textBox1_KeyPress(object sender, KeyPressEventArgs eventArgs)
    {
        _presenter.ValidateText1();
    }

    private void textBox2_KeyPress(object sender, KeyPressEventArgs eventArgs)
    {
        _presenter.ValidateText2();
    }

    #region Implementation of IMainView

    public string Text1
    {
        get { return textBox1.Text; }
    }

    public string Text2
    {
        get { return textBox2.Text; }
    }

    public string ErrorMessage
    {
        get { return labelErrorMessage.Text; }
        set { labelErrorMessage.Text = value; }
    }

    #endregion
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM