Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing the model in MVP Winforms App

I'm working on building up an MVP application (C# Winforms). My initial version is at Critique my simple MVP Winforms app ... Now I'm increasing the complexity. I've broken out the code to handle two separate text fields into two view/presenter pairs. It's a trivial example, but it's to work out the details of multiple presenters sharing the same model.

My questions are about the model:

  1. I am basically using a property changed event raised by the model for notifying views that something has changed. Is that a good approach? What if it gets to the point where I have 100 or 1000 properties? Is it still practical at that point?

  2. Is instantiating the model in each presenter with   NoteModel _model = NoteModel.Instance   the correct approach? Note that I do want to make sure all of the presenters are sharing the same data.

  3. If there is a better approach, I'm open to suggestions ....

My code looks like this:

NoteModel.cs

public class NoteModel : INotifyPropertyChanged
{
    private static NoteModel _instance = null;

    public static NoteModel Instance
    {
        get { return _instance; }
    }

    static NoteModel()
    {
        _instance = new NoteModel();
    }

    private NoteModel()
    {
        Initialize();
    }

    public string Filename { get; set; }
    public bool IsDirty { get; set; }
    public readonly string DefaultName = "Untitled.txt";

    string _sText;
    public string TheText
    {
        get { return _sText; }
        set
        {
            _sText = value;
            PropertyHasChanged("TheText");
        }
    }

    string _sMoreText;
    public string MoreText
    {
        get { return _sMoreText; }
        set
        {
            _sMoreText = value;
            PropertyHasChanged("MoreText");
        }
    }

    public void Initialize()
    {
        Filename = DefaultName;
        TheText = String.Empty;
        MoreText = String.Empty;
        IsDirty = false;
    }

    private void PropertyHasChanged(string sPropName)
    {
        IsDirty = true;

        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(sPropName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

TextEditorPresenter.cs

public class TextEditorPresenter
{
    ITextEditorView _view;
    NoteModel _model = NoteModel.Instance;

    public TextEditorPresenter(ITextEditorView view)//, NoteModel model)
    {
        //_model = model;
        _view = view;
        _model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
    }

    void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "TheText")
            _view.TheText = _model.TheText;
    }

    public void TextModified()
    {
        _model.TheText = _view.TheText;
    }

    public void ClearView()
    {
        _view.TheText = String.Empty;
    }
}

TextEditor2Presenter.cs is essentially the same except it operates on _model.MoreText instead of _model.TheText.

ITextEditorView.cs

public interface ITextEditorView
{
    string TheText { get; set; }
}

ITextEditor2View.cs

public interface ITextEditor2View
{
    string MoreText { get; set; }
}
like image 629
Keith G Avatar asked Sep 18 '09 17:09

Keith G


3 Answers

  1. This approach is good. However, if you are looking at having hundred (thousands even!) of Properties then I think you might have a God class (anti-pattern). There aren't many good classes with 100 properties. Instead consider breaking up your model into smaller classes. Furthermore, you don't need to have a separate event for each property. If the model is changed at all you can fire a single event (which might include information describing the change) and the views can handle it from there.
  2. I would avoid using the Singleton pattern unless you actually are sure you want it to apply. Instead, change the constructor for all your views to take in an instance of the model.
like image 87
tster Avatar answered Nov 18 '22 06:11

tster


Remember, in any layered application, it's normal for the domain model to transcend all layers.

  1. Thus, I would have your presenter pass your Note instance to the view (which no doubt is a Control of some sort), and then let databinding through a BindingSource take over. Once you're using databinding, then the controls will automatically listen to the PropertyChanged event and update accordingly without the need for extra code on your part. Event-based notification is the appropriate use here no matter how many properties are being monitored as only the objects that care about the change will take action (vs. having many objects taking action unnecessarily).

  2. Typically, you get your entity instances from a lower layer. For example, you could implement a service that returns your Note instances. Anytime you ask that service for Note #3, it returns the same instance of Note that it created from persisted data. You could further more add another item to your business layer to supplement your presenters - it could be call a WorkItem or a Controller. All of your presenters could consult their WorkItem instance to get the current instance of Note upon which the user will be working.

I would consider looking into examples of how the Composite Application Block (or CAB) uses these patterns to create smart client applications. It's all design patterns and OO principles, the implementation of which is well worth the effort.

like image 25
Travis Heseman Avatar answered Nov 18 '22 06:11

Travis Heseman


  • To Question 1: Implementing INotifyPropertyChanged seems to be a good idea to me. Probably you would however split the many properties into some classes.
  • To Question 2: I am currently using a Singleton pattern for sharing my MVP Model with multiple presenters. I am happy so far, as this guarantees, that there is really ever only one instance of my model.
like image 1
Marcel Avatar answered Nov 18 '22 05:11

Marcel