Problem

The forms in a smart client application frequently contain various controls, handle user events, and contain logic to alter the controls in response to these events. Writing this code in the form class makes the class complex and difficult to test. In addition, it is difficult to share code between forms that require the same behavior.

Solution

Example code

    interface IShapeView
    {
        IList<Shape> Shapes { get; }
        void SelectShape(Shape shape);
        void UnSelectAll();
        void Refresh();
    }

    class ShapeView : UserControl, IShapeView
    {
        private readonly Presenter presenter;
        private readonly Button addShapeButton;

        public View(Presenter presenter)
        {
            this.presenter = presenter;
            this.Shapes = new List<Shape>();
            this.addShapeButton.Click += AddShapeClicked;
        }

        public IList<Shape> Shapes { get; }

        private void AddShapeClicked(object sender, EventArgs args)
        {
            this.presenter.AddNewShape();
        }

        public void SelectShape(Shape shape)
        {
            // select shape on canvas
            // Refresh the view (can also be done through events)
            this.Refresh();
        }

        public void UnSelectAll()
        {
            // un select all shapes on canvas and refresh
            this.Refresh();
        }

        public void Refresh()
        {
            // refresh the canvas
        }

    }

    class ShapeViewPresenter
    {
        IShapeView View { get; set; }

        public void AddNewShape()
        {
            // Create shape geometry..
            var newShape = CreateNewShape();

            // Add new shape logic to model and view..
            View.Shapes.Add(newShape);

            //Select the new shape in the view
            View.SelectShape(newShape);
        }

        private static Shape CreateNewShape()
        {
            // create or get the shape from a repository
            return new Shape();
        }
    }

    class Shape
    {
        // The model
    }

Advantages

• Clean seperation of concerns
• Simple views wich can easily re-factored by replacing UI components or complete views implementation without big changes in the view logic wich resided in the presenter
• Unit testing presenter is easier then unit testing the view

Disadvantages

• The pattern is complex and may be unnecessary for simple screens.
• The pattern is one more thing to learn for busy developers: there's some overhead.
• It can be hard to debug events being fired in active Model-View-Presenter.
My personal view is that even if you think this is a useful pattern (and it is) you shouldn't use it indiscriminately on every screen in your application. You should use it where you have reasonably complex logic which will benefit from splitting the user interface classes in this way.

Conclusion

Use only when view logic gets complex. For simple views it is easier to leave out the presenter.

  • No labels