WPF MVVM Code Behind Best Practices - c#

I'm a student learning C# with WPF using the MVVM pattern. Recently I have been working on a [art of my application (a custom splash screen) that should not be closed when I don't want it to.
I have been searching the web for a good way of doing this without code-behind. Unfortunately after days I still did not find a satisfying way.
Then I came to think of a way to do it myself, with help of just one line of code in the constructor of my view. It still makes my code testable and decouples the code from the View. The question is, is there a better way of doing what I'm trying to do:
My interface for my ViewModel
public interface IPreventCloseViewModel
{
bool PreventClose { get; set; }
}
The extension for the View
public static class PreventCloseViewModelExtension
{
/// <summary>
/// Use this extension method in the constructor of the view.
/// </summary>
/// <param name="element"></param>
public static void PreventCloseViewModel(this Window element)
{
var dataContext = element.DataContext as IDisposable;
if (dataContext is IPreventCloseViewModel)
{
element.Closing += delegate(object sender, CancelEventArgs args)
{
if (dataContext is IPreventCloseViewModel)
{
args.Cancel = (dataContext as IPreventCloseViewModel).PreventClose;
}
};
}
}
}
The code-behind for the View
public partial class SplashScreen
{
public SplashScreen()
{
InitializeComponent();
this.PreventCloseViewModel();
}
}

MVVM does not mean that you cannot use Code-Behind.
MVVM means that your application logic should not be tied to UI elements.
You can perfectly well handle events in code behind (such as Window.Closing), and "send messages" or execute methods in the ViewModel to react to that.
Here, you are not breaking MVVM by placing the event handler in code behind. You would be breaking MVVM if you were placing the logic that determines whether the application can be closed in code behind. That is a responsibility of the application logic, and the application logic lives in ViewModels, not Views.

I usually have a generic Shell class which subclasses Window and does something like:
public Shell()
{
InitializeComponent();
this.Closing += (s,e) =>
{
var canClose = Content as ICanClose;
if (canClose != null)
e.Cancel = !canClose.CanClose;
}
}
That way it does not matter what kind of view model you put in, if it implements the interface that will be taken into account.
Don't see much point in externalizing the logic, and it's fine in terms of the MVVM pattern.

Related

Can we raise an event from ViewModel to View?

For example, my ViewModel do something. After that, I wanted to notify my View in order to do something that should only be done in View.
Something like;
public class MyViewModel : ViewModelBase{
...
private void DoSomething(){
//raise the event here and notify the View
}
}
then in View;
public MyView(){
InitializeComponent();
...
}
private void ViewModelSaidDoSomething(){
//The View Model raises an event, do something here about it...
}
is that possible without breaking the MVVM concept?
Yes, it's possible. Usually, what you can do is define the event from your ViewModel, then let your View subscribe from that event.
For example, in your ViewModel.
public class MyViewModel : ViewModelBase{
...
//Define your event.
public delegate void YourEventAction(string your_argument);
public event YourEventAction? YourEvent;
private void DoSomething(){
YourEvent?.Invoke(your_argument); //raise the event here, any subscriber will received this.
}
}
Then you can subscribe for that event in your View.
public MyView(){
InitializeComponent();
...
DataContextChanged += ViewModelSaidDoSomething; //subscribe to DataContextChanged.
}
private void ViewModelSaidDoSomething(){
var viewModel = (MyViewModel)DataContext; //Get your ViewModel from your DataContext.
viewModel.YourEvent += (your_argument) =>{ //Subscribe to the event from your ViewModel.
//The View Model raises an event, do something here about it...
};
}
Hope that helps.
My primary candidate for any viewmodel <-> view communication would be binding.
This is a weak event pattern, late binding and the view doesn't need to be aware of what type the viewmodel is. They went to a load of trouble to implement binding and it works well IMO. Anyhow, binding means view and viewmodel are as loosely coupled as you can get whilst retaining reasonable practicality.
Here's an example.
The purpose is to allow a viewmodel to close a window.
The view functionality is encapsulated in a control.
Only code.
public class CloseMe : Control
{
public bool? Yes
{
get
{
return (bool?)GetValue(YesProperty);
}
set
{
SetValue(YesProperty, value);
}
}
public static readonly DependencyProperty YesProperty =
DependencyProperty.Register("Yes",
typeof(bool?),
typeof(CloseMe),
new PropertyMetadata(null, new PropertyChangedCallback(YesChanged)));
private static void YesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool?)e.NewValue != true)
{
return;
}
CloseMe me = (CloseMe)d;
Window parent = Window.GetWindow(me) as Window;
parent.Close();
}
}
Anywhere in a window or usercontrol goes in the window you want to close:
<local:CloseMe Yes="{Binding CloseYes, Mode=TwoWay}"/>
That binds to a bool property CloseYes in the viewmodel. Set that true and the window closes.
We can imagine encapsulating some data in a more complicated viewmodel object instead of just a boolean. That would not be quite so elegant though.
A view isn't supposed to process data, so I'd question what you're doing if you're sending complex data.
Setting those doubts aside though.
If you wanted to transfer a complex type from A to B with loose coupling then the pub sub pattern is a good candidate.
The mvvm toolkit is my framework of preference and there's an implementation in there which you can use. Messenger:
https://learn.microsoft.com/en-us/windows/communitytoolkit/mvvm/messenger
The message sent is an object you define and you can use WeakReferenceMessenger. Which does what it implies and relies on a weak reference. Thus reducing the risk of memory leaks.
Other frameworks have similar mechanisms so you could take a look at what's in the one you prefer.

Windows Forms, Designer, and Singleton

I'm trying to work with Windows Forms and User Controls and thus far it's been nothing but a headache. I can't make the form or the controls static because the designer doesn't like that and when I use Singleton on my form and controls, the designer still throws errors at me.
My FormMain:
public partial class FormMain : Form
{
private static FormMain inst;
public static FormMain Instance
{
get
{
if (inst == null || inst.IsDisposed)
inst = new FormMain();
return inst;
}
}
private FormMain()
{
inst = this;
InitializeComponent();
}
MainScreen.cs:
public partial class MainScreen : UserControl
{
private static MainScreen inst;
public static MainScreen Instance
{
get
{
if (inst == null || inst.IsDisposed)
inst = new MainScreen();
return inst;
}
}
private MainScreen()
{
inst = this;
InitializeComponent();
}
If the constructor of MainScreen is public the program runs, but when I change it to private I now get an error in FormMain.Designer.cs saying "'Adventurers_of_Wintercrest.UserControls.MainScreen.MainScreen()' is inaccessible due to its protection level". It points to this line:
this.controlMainScreen = new Adventurers_of_Wintercrest.UserControls.MainScreen();
I think this is the instance of the class that the designer makes by default. Should I ditch the designer? Or is there a way around this? Or is there another way to make class properties accessible without using Singleton (since I can't seem to make the form or controls static)? Any help would be greatly appreciated.
You need to keep a reference to each instance of each form if you want to access the public properties of the instantiated form.
One way is to have a class with a static variable for each type of form:
class FormReferenceHolder
{
public static Form1 form1;
public static Form2 form2;
}
This way you would set the static variable whenever you instantiate a form, and then you can access that variable from anywhere in the program. You can go one step further with this and use properties that set up the form if it doesn't already exist:
class FormReferenceHolder
{
private static Form1 form1;
public static Form1 Form1
{
get
{
if (form1 == null) form1 = new Form1();
return form1 ;
}
}
}
...
static void Main()
{
Application.Run(FormReferenceHolder.Form1 );
}
I think I answered a previous question about this, which looks like it is what got you started down this route. The first point is that I wasn't recommending this pattern specifically, just trying to teach you more about how software developers can manage scope.
That said, the problem you are facing isn't insurmountable. You could hobble a public constructor by throwing an exception at runtime and not at design time, for instance, and modify Program.cs to use the static Instance instead of manually constructing the form.
But.
As I said in the other question, the better option would be to change architecture so that you don't need your library code to directly manipulate the GUI in the first place.
You can do this either by just having the GUI ask the library questions when it thinks it needs new data (simple functions) or by letting the GUI be notified when something needs to change. Either method would be better than having the library fiddle with labels directly.
A good place to start would be something like an MVC (model-view-controller) architecture, which I was alluding to in my previous answer. It might be best, though, to give us an idea of what your high-level program structure looks like now on a bit more detail. What are the main classes you are using in your system (not just the ones you've mentioned so far)? What is the main responsibility of each, and where does each live? Then our recommendations could be a little more specific.
EDIT
So, I have mocked up a quick demo of a possible alternative architecture, based on your comment.
I have the following in my project:
FormMain (Form)
TitleScreen (UserControl)
InGameMenu (UserControl)
MainScreen (UserControl)
GameController (Class)
GameModel (Class)
I didn't use Date and LoadSave, for now.
FormMain simply has an instance of each UserControl dropped on it. No special code.
GameController is a singleton (since you tried to use this pattern already and I think it would be helpful for you to try using a working version of it) that responds to user input by manipulating the model. Note well: you don't manipulate the model directly from your GUI (which is the View part of model-view-controller). It exposes an instance of GameModel and has a bunch of methods that let you perform game actions like loading/saving, ending a turn, etc.
GameModel is where all your game state is stored. In this case, that's just a Date and a turn counter (as if this were going to be a turn-based game). The date is a string (in my game world, dates are presented in the format "Eschaton 23, 3834.4"), and each turn is a day.
TitleScreen and InGameMenu each just have one button, for clarity. In theory (not implementation), TitleScreen lets you start a new game and InGameMenu lets you load an existing one.
So with the introductions out of the way, here's the code.
GameModel:
public class GameModel
{
string displayDate = "Eschaton 23, 3834.4 (default value for illustration, never actually used)";
public GameModel()
{
// Initialize to 0 and then increment immediately. This is a hack to start on turn 1 and to have the game
// date be initialized to day 1.
incrementableDayNumber = 0;
IncrementDate();
}
public void PretendToLoadAGame(string gameDate)
{
DisplayDate = gameDate;
incrementableDayNumber = 1;
}
public string DisplayDate
{
get { return displayDate; }
set
{
// set the internal value
displayDate = value;
// notify the View of the change in Date
if (DateChanged != null)
DateChanged(this, EventArgs.Empty);
}
}
public event EventHandler DateChanged;
// use similar techniques to handle other properties, like
int incrementableDayNumber;
public void IncrementDate()
{
incrementableDayNumber++;
DisplayDate = "Eschaton " + incrementableDayNumber + ", 9994.9 (from turn end)";
}
}
Things to note: your model has an event (in this case, just one of type EventHandler; you could create more expressive types of events later, but let's start simple) called DateChanged. This will be fired whenever DisplayDate changes. You can see how that happens when you look at the property definition: the set accessor (which you will NOT call from your GUI) raises the event if anyone is listening. There are also internal fields to store game state and methods which GameController (not your GUI) will call as required.
GameController looks like this:
public class GameController
{
private static GameController instance;
public static GameController Instance
{
get
{
if (instance == null)
instance = new GameController();
return instance;
}
}
private GameController()
{
Model = new GameModel();
}
public void LoadSavedGame(string file)
{
// set all the state as saved from file. Since this could involve initialization
// code that could be shared with LoadNewGame, for instance, you could move this logic
// to a method on the model. Lots of options, as usual in software development.
Model.PretendToLoadAGame("Eschaton 93, 9776.9 (Debug: LoadSavedGame)");
}
public void LoadNewGame()
{
Model.PretendToLoadAGame("Eschaton 12, 9772.3 (Debug: LoadNewGame)");
}
public void SaveGame()
{
// to do
}
// Increment the date
public void EndTurn()
{
Model.IncrementDate();
}
public GameModel Model
{
get;
private set;
}
}
At the top you see the singleton implementation. Then comes the constructor, which makes sure there's always a model around, and methods to load and save games. (In this case I don't change the instance of GameModel even when a new game is loaded. The reason is that GameModel has events and I don't want listeners to have to unwire and rewire them in this simple sample code. You can decide how you want to approach this on your own.) Notice that these methods basically implement all the high-level actions your GUI might need to perform on the game state: load or save a game, end a turn, etc.
Now the rest is easy.
TitleScreen:
public partial class TitleScreen : UserControl
{
public TitleScreen()
{
InitializeComponent();
}
private void btnLoadNew(object sender, EventArgs e)
{
GameController.Instance.LoadNewGame();
}
}
InGameMenu:
public partial class InGameMenu : UserControl
{
public InGameMenu()
{
InitializeComponent();
}
private void btnLoadSaved_Click(object sender, EventArgs e)
{
GameController.Instance.LoadSavedGame("test");
}
}
Notice how these two do nothing but call methods on the Controller. Easy.
public partial class MainScreen : UserControl
{
public MainScreen()
{
InitializeComponent();
GameController.Instance.Model.DateChanged += Model_DateChanged;
lblDate.Text = GameController.Instance.Model.DisplayDate;
}
void Model_DateChanged(object sender, EventArgs e)
{
lblDate.Text = GameController.Instance.Model.DisplayDate;
}
void Instance_CurrentGameChanged(object sender, EventArgs e)
{
throw new NotImplementedException();
}
private void btnEndTurn_Click(object sender, EventArgs e)
{
GameController.Instance.EndTurn();
}
}
This is a little more involved, but not very. The key is, it wires up the DateChanged event on the model. This way it can be notified when the date is incremented. I also implemented another game function (end turn) in a button here.
If you duplicate this and run it, you'll find that the game date is manipulated from lots of places, and the label is always updated properly. Best of all, your controller and model don't actually know anything at all about the View-- not even that it's based on WinForms. You could as easily use those two classes in a Windows Phone or Mono context as anything else.
Does this clarify some of the architecture principles I and others have been trying to explain?
In essence the problem is that when the application runs, it's going to try to instantiate the main form-window. But by using the Singleton pattern, you're essentially forbidding the application from doing that.
Take a look at the sample code here:
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.aspx
You'll notice in particular this section:
[STAThread]
public static void Main()
{
// Start the application.
Application.Run(new Form1());
}
Notice how the program is trying to instantiate Form1. Your code says, nah, I don't really want that since you mark the constructor as private (same holds true for static forms as well). But that's counter to how windows forms is supposed to work. If you want a singleton form-window, just don't make any more. Simple as that.

WinForm and Class interaction

I have two classess and a Userform. I am trying not to use any Form related code in my classess but i am rather new to OOP. In the CreateGraph() method, i would like to prompt the user with a Yes/No dialog. The code in the method would continue based on the result. I have read some examples on MVP but not exactly sure how i can implement in this case.
Can someone guide me on this? I do believe there is some serious design issues in my code
//singleton class
public class MyApplication
{
private int state;
private static MyApplication instance = null;
public void Task1()
{
GraphGenerator gg = new GraphGenerator();
gg.CreateGraph();
state = 1;
}
public void Task2()
{
//some other tasks..
state = 2;
}
}
Class where i have issue..
public class GraphGenerator
{
public void CreateGraph()
{
//some code for creating a graph..
//here i want to prompt the user with a
// Yes/No dialog box..
}
}
The userform
public partial class Form1 : Form
{
private void btnTask1_Click(object sender, EventArgs e)
{
MyApplication ma = MyApplication.Instance;
ma.Task1();
}
private void btnTask1_Click(object sender, EventArgs e)
{
MyApplication ma = MyApplication.Instance;
ma.Task2();
}
}
Naming - MyApplication - is bad name for controller or presenter, use for example "form name" + "presenter" for naming.
Singleton. Controller or presenter should not be singleton. Inject it through constructor or create in ctor and than save to field or property with private setter in class. For example:
public Form1(FormPresenter presenter)
{
InitializeComponent();
this.presenter = presenter;
}
All other on this simple sample is normal. But for buttons event handlers you can use events in presenter/controller and fire in button event handler specific to presenter/controller events.
Also try to look for MVC/MVP frameworks. Look here for related question:
Implementing MVC with Windows Forms
As I remember there is Microsoft Smart Client Guidance (CAB / Microsoft Composite Application Block) for that.
First , it is best to design your classes as much as possible such that you don't need to intermingle UI code with your domain objects. Can you restructure the code so that the caller/owner of GraphGenerator decides if it needs to ask the user something instead of GraphGenerator doing it? Try to keep GraphGenerator solely focused on his task or making graphs.
Failing that, you could define events (or delegates or callback interface, but lets call these related mechanisms events for now) within GraphGenerator such that the caller/owner can listen for notifications from GraphGenerator and in turn interact with the user. For example, define an event called QueryConfirmSave to raise and the caller can handle the event and prompt the user and then pass back a boolean as an EventArg field.
(The code would be something like this (from the hip, not editor checked):
GraphGenerator gg = new GraphGenerator();
gg.QueryConfirmSave += new EventHandler<ConfirmSaveArgs>(GraphGenerator_QueryConfirmSave);
and then:
private void GraphGenerator_QueryConfirmSave(object sender, ConfirmSaveArgs args)
{
if (MessageBox.Show("Save?") == DialogResult.Yes)
{
args.SaveConfirmed = true;
}
}
You need MessageBox.Show(...).

Unable to cast object of type

I get an error trying to send a string from one window to another in my wpf application:
Unable to cast object of type 'WpfApplication4.LoginWindow' to type 'WpfApplication4.MainWindow'.
In my login window the error is on this line:
((MainWindow)Application.Current.MainWindow).StudentID = UserAuthenticationID;
In my main window I have this to test:
public string StudentId { get; set; }
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
label1.Content = StudentID;
}
What am I doing wrong?
EDIT:
No answer has made sense so far, which will be due to my obscure question, I created a wpf application and I have two windows MainWindow.xaml and LoginWindow.xaml.
I want to pass a string (student id) from the login window to the main window after authentication.
I thought the above method was how to do it, as I read it: ((MainWindow)Application.Current.MainWindow).StudentID says where I am intending the string UserAuthenticationID to be sent to?
Then in the MainWindow.xaml I get the string UserAuthenticationID and set it, I then assign a labels content to this public string?
Presumably you create your login window from your main window. If you need to reference your main window from your login window then pass a main window reference to your login window when you construct it. Eg
void MainWindow_Loaded(object sender, RoutedEventArgs e) {
LoginWindow login = new LoginWindow(this);
login.ShowDialog();
}
class LoginWindow : Window {
MainWindow app_window;
public LoginWindow(MainWindow app_window) {
Owner = app_window;
this->app_window = app_window;
}
}
Error coming because its trying to convert Application.Current.MainWindow to MainWindow, which is infact LoginWindow.
suggestion when you are coverting one object other made check before it
if(Application.Current.MainWindow is MainWindow)
{
/// than do the code
}
It looks like your trying to feed the UserAuthenticationID from your login dialog back to your main window where you store it as StudentId.
Why not handle that back in the main window Eg:
if (login.ShowDialog())
StudentId = login.UserAuthenticationID;
It seems that your Application.Current.MainWindow is of Type LoginWindow. But you want to cast it to MainWindow. Both derive (maybe) from Window. But you can't cast a derived class to another derived class.
//Edit
try
((LoginWindow)Application.Current.MainWindow)
or change your Application.Current.MainWindow to a object of type MainWindow
//Edit 2
I think i understood what your intention was. You could try the following:
In your LoginWindow where you press the Button "Login" handle the Buttonevent (Click), get the ID whereever it comes (TextBox) from, put it in a new instance of MainWindow and set the
Application.Current.MainWindow
to the new instance of MainWindow. If I'm wrong on how you will do it, you should give more facts.
Other solution is the LoginDialog solution from Ricibob.
You need to restructure the design of your program. What you want to do isn't terribly hard; you're essentially asking for a good way to communicate between forms.
First off, I suggest not using Application.Current.MainWindow unless you're really sure you need to. You can get apps to work using it, but it's not good design and leads to problems.
We'll start off with the definition of some OtherWindow that will be the popup.
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for OtherWindow.xaml
/// </summary>
public partial class OtherWindow : Window
{
public OtherWindow()
{
InitializeComponent();
}
public string SomeData
{
get
{
//you'll probably want to return the value of a textbox or something else
//the user fills in.
return "Hello World!";
}
}
}
}
From a communication point of view, all that's really important is that it has a property (or properties) with the information that the main form will need to access. Obviously I've omitted all of the code for actually collecting the data to return and instead hard code a value for this example.
Now for the mainform. (All I've added is a button and a label.)
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
OtherWindow other = new OtherWindow();
other.Closed += (sender2, e2) =>
{
label1.Content = other.SomeData;
};
//either of the methods below, depending on desired behavior.
other.Show();
//other.ShowDialog();
}
}
}
While there are quite a lot of ways of making different windows/forms communicate, this is my favorite. All of the logic for the interaction between the windows is in once place (the button click event). The main form clearly "owns" OtherWindow, and OtheWindow doesn't need to know a thing about MainWindow, it only need to know how to collect some information. MainWindow will take care of pulling out the information that it needs.
The code for the button click even reads just like what you want it to do: create a new window, when it's closed, set its content to my label, and show the form. It's all in once place, and in the order that I logically think through it (you can attach the event handler after Show if you want).
Oh, and this is exactly the same way that I would do this in a winforms app too, in case anyone cares, barring the fact that some of the class/property names will be different.

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:
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?
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.
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; }
}
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.
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.
Remember, in any layered application, it's normal for the domain model to transcend all layers.
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).
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.
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.

Categories

Resources