2
\$\begingroup\$

I asked the following question on stackoverflow and as a result came up with the following code to avoid circular event logic when using winforms.

There are two occasions where my model can be updated, either programmatically via some application logic, or by the user via a view.

There is no longer any circular logic but there is still superfluous behaviour. When I update my model via the property in the presenter, the view gets updated, which in turn fires an event to update the model in the presenter (again). I can probably just about live with that, but it still irks me. (EDIT: Actually I can't live with that. It's not too bad here because the view has only two TextBoxes, hence the text changed event gets fired twice, updating the model two different times. This would be even worse if the control had multiple textboxes).

Is it correct to expose my model via a property in the presenter? Should I always use this instance to refer to the actual model? How else can I programmatically update my model and have the view updated?

public partial class View : UserControl
{
    private Model model = new Model();

    public View()
    {
        InitializeComponent();
    }

    public event EventHandler<Model> DataUpdated;

    public Model Model
    {
        get
        {
            return model;
        }
        set
        {
            if (value != null)
            {
                model = value;
                UpdateTextBoxes();
            }
        }
    }

    private void UpdateTextBoxes()
    {
        if (InvokeRequired)
        {
            Invoke(new Action(() => UpdateTextBoxes()));
        }
        else
        {
            textBox1.Text = model.Text1;
            textBox2.Text = model.Text2;
        }
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        model.Text1 = ((TextBox)sender).Text;
        OnModelUpdated();
    }

    private void textBox2_TextChanged(object sender, EventArgs e)
    {
        model.Text2 = ((TextBox)sender).Text;
        OnModelUpdated();
    }

    private void OnModelUpdated()
    {
        DataUpdated?.Invoke(this, model);
    }
}

public class Model
{
    public string Text1 { get; set; }
    public string Text2 { get; set; }
}

public class Presenter
{
    private Model model;
    private View view;

    public Presenter(Model model, View view)
    {
        this.model = model;
        this.view = view;

        view.DataUpdated += View_DataUpdated;
    }

    public Model Model
    {
        get
        {
            return model;
        }
        set
        {
            model = value;
            view.Model = model;
        }
    }

    private void View_DataUpdated(object sender, Model e)
    {
        //This is fine.
        model = e;

        //This causes the circular dependency.
        //Model = e;
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ If you implemented IPropertyChanged then set the TextBox.DataBindings property. See Change Notification in Win Forms Data Binding. Otherwise, maybe the view should not be handling TextChanged nor property changed events, rather button click or leave or lose focus events; depending on how you want the screen to behave. \$\endgroup\$ – radarbob Jul 25 '16 at 13:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.