Avoid instantiate object when every time constructor being called - c#

I have a PersonViewModel class and bind with Person User Control. Everytime when I select Person Use Control page, createPersonCommand, deletePersonCommand, viewPersonCommand will always reinstantiate. Are there any ideas to create those command once ? Execpt for InitializePersonCollection method because will retrieve latest date from DB.
My senior comments on my assignment, and he was mentioned on this.
private ICommand createPersonCommand;
public ICommand CreatePersonCommand
{
get { return createPersonCommand; }
}
private ICommand deletePersonCommand;
public ICommand DeletePersonCommand
{
get { return deletePersonCommand; }
}
private ICommand viewPersonCommand;
public ICommand ViewPersonCommand
{
get { return viewPersonCommand; }
}
public PersonViewModel()
{
createPersonCommand = new DelegateCommand<object>(ExecuteCreatePersonCommand);
deletePersonCommand = new DelegateCommand<object>(ExecuteDeletePersonCommand);
viewPersonCommand = new DelegateCommand<object>(ExecuteViewPersonCommand);
InitializePersonCollection();
}

As long as the command executing methods are not static, you will need to do this. If for whatever reason you can make the command methods static, you could make your DelegateCommands static as well and only assign the static instances to your members.
But as people already mentioned, that would not make sense. The code you have is a well established pattern. There is no reason to change it.
Maybe you should check if the commands are actually well placed. Does every person need it's own command, or do you need commands in your main viewmodel that get a single person as parameter? That might make more sense.

You can use "lazy-loading". Then commands will be instantiated on-demand and will not affect speed of loading data from database.
private ICommand createPersonCommand;
public ICommand CreatePersonCommand
{
get {
if (createPersonCommand == null) {
createPersonCommand = new DelegateCommand<object>(ExecuteCreatePersonCommand)
}
return createPersonCommand;
}
}

Related

Updating ObservableCollection using delegates in MVVM?

I have three ViewModels: MainViewModel, PreferencesViewModel and ColourControllerViewModel - the latter 2 are properties of the MainViewModel.
ColourControllerViewModel is used for the 'ColourSelector' view, where various colours can be created and deleted. It contains an ObservableCollection of ColourViewModel, which has a property detailing the colour, and a bool property determining if it should be shown on the preferences tab (DisplayOnPreferences).
PreferencesViewModel is used for the 'Preferences' view, which contains a combo box of colours - this is represent by an ObservableCollection of ColourViewModel, and only those ColourViewModels where DisplayOnPreferences == true should be displayed.
My question is, what's the easiest way to do this? Currently, I am using an Action delegate called UpdateList() which passes the updated list from ColourControllerViewModel to MainViewModel, which in turn updates the PreferencesViewModel. I don't really like this though, it feels like there's a better way.
Should there be a single ObservableCollection of ColourViewModel on MainViewModel that is updated/accessed by either instance?
Here are the classes:
public class MainViewModel : ViewModel
{
private ColourMappingControllerViewModel _colourMappingControllerViewModel;
private PreferencesControllerViewModel _preferencesTabViewModel;
public MainViewModel()
{
// Initialise the database Handler
dbHandler = DatabaseHandler.DbHandlerInstance;
_colourMappingControllerViewModel = new ColourMappingControllerViewModel(dbHandler.GetColourMappingsList(), UpdateColourList);
_preferencesTabViewModel = new PreferencesControllerViewModel(dbHandler.GetPreferences, ColourMappingList)
}
public ObservableCollection<ColourMappingViewModel> ColourMappingList
{
get { return ColourMappingControllerViewModel.ColourMappingList; }
}
public void UpdateColourList(ObservableCollection<ColourMappingViewModel> colourList)
{
PreferencesTabViewModel.UpdateColourList(colourList);
}
}
public class ColourMappingControllerViewModel : ViewModel
{
public ColourMappingControllerViewModel(IEnumerable<ColourMapping> colourMappingsList, Action<ObservableCollection<ColourMappingViewModel>> updateColourListAction)
{
InitialiseCommands();
ColourMappingList = new ObservableCollection<IColourMappingViewModel>(InitialiseColourMappingsList(colourMappingsList));
}
public ICommand AddColourMappingCommand { get; set; }
private void InitialiseCommands()
{
AddColourMappingCommand = new DelegatingCommand(AddColourMapping);
}
private void AddColourMapping() // Attached to Command on View
{
var newColourMapping = new ColourMappingViewModel(
new ColourMapping());
ColourMappingList.Add(newColourMapping);
ColourMappingsCollectionView.MoveCurrentToLast();
UpdateColourMappingList();
}
private void UpdateColourMappingList()
{
UpdateColourListAction.Invoke(ColourMappingList);
}
}
public PreferencesControllerViewModel : ViewModel
{
public PreferencesControllerViewModel(object preferenceInfo, ObservableCollection<ColourMappingViewModel> colourMappingsList)
{
var pciTrendBlocks = pciBlocks;
ColourMappingsList = colourMappingsList;
}
public void UpdateColourList(ObservableCollection<ColourMappingViewModel> colourList)
{
ColourMappingsList = colourList;
}
}
I know the ObservableCollection class is being misused - it's probably not necessary on the Preferences as it will only be updated in ColourMappingController.
I would agree that you need a single ObservableCollection that is shared between views. This effectively becomes your "Model" in MVVM.
You may also want to enforce different access semantics by having a ReadOnlyObservableCollection that can be passed to your preferences VM etc. This ensures that only ColourControllerViewModel (Which gets the underlying ObservableCollection) can actually alter the collection.
In my apps I tend to have a separate data layer, but yes, for now it would be simplest to just add them to MainViewModel.
The alternative would be to have ColourControllerViewModel be the thing that owns the collection (and exposes it as a ReadOnlyObservableCollection), and have you MainViewModel just pass the collection into any other VM's that need it.

What is my mistake in implementing an asynchronous RelayCommand?

I am learning WPF and MVVM at the moment and I faced a problem when i tried to write unit tests for a viewmodel, whose commands invoke async methods. That problem is well-described in this question. That question also has a solution: to write a new Command class with an additional awaitable method that can be awaited in unit tests. But since i use MvvmLight, i decided not to write a new class, but to inherit from the built-in RelayCommand class instead. However, i don't seem to understand how to do it properly. Below is a simplified example that illustrates my problem:
AsyncRelayCommand:
public class AsyncRelayCommand : RelayCommand
{
private readonly Func<Task> _asyncExecute;
public AsyncRelayCommand(Func<Task> asyncExecute)
: base(() => asyncExecute())
{
_asyncExecute = asyncExecute;
}
public AsyncRelayCommand(Func<Task> asyncExecute, Action execute)
: base(execute)
{
_asyncExecute = asyncExecute;
}
public Task ExecuteAsync()
{
return _asyncExecute();
}
//Overriding Execute like this fixes my problem, but the question remains unanswered.
//public override void Execute(object parameter)
//{
// _asyncExecute();
//}
}
My ViewModel (based on the default MvvmLight MainViewModel):
public class MainViewModel : ViewModelBase
{
private string _welcomeTitle = "Welcome!";
public string WelcomeTitle
{
get
{
return _welcomeTitle;
}
set
{
_welcomeTitle = value;
RaisePropertyChanged("WelcomeTitle");
}
}
public AsyncRelayCommand Command { get; private set; }
public MainViewModel(IDataService dataService)
{
Command = new AsyncRelayCommand(CommandExecute); //First variant
Command = new AsyncRelayCommand(CommandExecute, () => CommandExecute()); //Second variant
}
private async Task CommandExecute()
{
WelcomeTitle = "Command in progress";
await Task.Delay(1500);
WelcomeTitle = "Command completed";
}
}
As far as i understand it, both First and Second variants should invoke different constructors, but lead to the same result. However, only the second variant works the way i expect it to. The first one behaves strangely, for example, if i press the button, that is binded to Command once, it works ok, but if i try to press it a second time a few seconds later, it simply does nothing.
My understanding of async and await is far from complete. Please explain me why the two variants of instantiating the Command property behave so differently.
P.S.: this behavior is noticeable only when i inherit from RelayCommand. A newly created class that implements ICommand and has the same two constructors works as expected.
OK, I think I found the problem. RelayCommand uses a WeakAction to allow the owner (target) of the Action to be garbage collected. I'm not sure why they made this design decision.
So, in the working example where the () => CommandExecute() is in the view model constructor, the compiler is generating a private method on your constructor that looks like this:
[CompilerGenerated]
private void <.ctor>b__0()
{
this.CommandExecute();
}
Which works fine because the view model is not eligible for garbage collection.
However, in the odd-behavior example where the () => asyncExecute() is in the constructor, the lambda closes over the asyncExecute variable, causing a separate type to be created for that closure:
[CompilerGenerated]
private sealed class <>c__DisplayClass2
{
public Func<Task> asyncExecute;
public void <.ctor>b__0()
{
this.asyncExecute();
}
}
This time, the actual target of the Action is an instance of <>c__DisplayClass2, which is never saved anywhere. Since WeakAction only saves a weak reference, the instance of that type is eligible for garbage collection, and that's why it stops working.
If this analysis is correct, then you should always either pass a local method to RelayCommand (i.e., do not create lambda closures), or capture a (strong) reference to the resulting Action yourself:
private readonly Func<Task> _asyncExecute;
private readonly Action _execute;
public AsyncRelayCommand(Func<Task> asyncExecute)
: this(asyncExecute, () => asyncExecute())
{
}
private AsyncRelayCommand(Func<Task> asyncExecute, Action execute)
: base(execute)
{
_asyncExecute = asyncExecute;
_execute = execute;
}
Note that this actually has nothing to do with async; it's purely a question of lambda closures. I suspect it's the same underlying issue as this one regarding lambda closures with Messenger.

MVVM and INotifyPropertyChanged Issue

I have a big problem with MVVM design. I am trying to catch every PropertyChanged of my inner nested objects, including futhermore propertchanged of their nested objects, inside my ViewModel but I dont know how to do it.
Here is my structure:
class MyVM
{
public MyVM()
{
this.SomeData = new SomeData();
this.SomeData.NestedObj = new MyNestedDat();
this.SomeData.Str = "This tiggers propertychanged inside MyDat class";
// this triggers propertychanged event inside MyNestedDat class
this.SomeData.NestedObj.Num = 123;
}
// and here should be a method where i catch all possibe propertychanges from my nested objets and their nested objets, how do i do that?
public MyDat SomeData
{
get;
set;
}
}
class MyDat : INotifyPropertyChanged
{
private string str;
public string Str;
{
get { return this.str;}
set
{
this.str = value;
this.PropertyChanged(this, "Str");
}
}
publicMyNestedDat NestedObj
{
get;
set;
}
}
class MyNestedDat : INotifyPropertyChanged
{
private int num;
public int Num
{
get{ return this.num;}
set
{
this.num = value;
this.PropertyChanged(this, "Num");
}
}
}
How do i get this to work? I am really clueless where to start.
MyNestedDat class throws PropertyChanged, MyDat class throws propertychanged and i want to catch them all inside my viewmodel. How can i do that?
In my opinion there are a few conceptual things wrong with what you are asking. Just imagine you get a solution that works for your scenario (that you are happy with) and consider the following:
What happens if another layer is added? do you still expect it to work the same?
Should property changes be propagated (viewModel1.propA notifies viewModel2.PropA)?
Should property changes be transformed (viewModel1.SomeProp notifies ViewModel2.AnotherProp)?
Is performance a concern? how will this perform if you need to propagate the property changed events through many levels?
This should be raising alarm bells that the current approach is not the right path to tread.
What you need is a way to provide communication between your viewModels in a loosely coupled way so that you viewModels do not even need to know about each others existence. The beauty of this is that this will also work in other situations not just for property changes.
For your case of property changed events, one viewModel wants to know when something happens (it could be something other than a property changed event, remember). This means the other viewModel needs some way of saying "Hey, a property has changed" (or "My state has changed", "That database call has finished" etc).
Now in C# you can provide events which provide this feature....except, now your objects know about each other which leaves you with the same problem you had before.
To overcome this problem you need another object, a mediator (lets call it Messenger in this example), whose sole purpose is to handle the message passing between the objects so that they can live in ignorance of each other.
The general idea is this. In the viewModel that provides notifications you might do something like this:
public string MyProp
{
get { return _myProp; }
set
{
_mProp = value;
OnPropertyChanged("MyProp");
Messenger.PostMessage(new VMChangedMessage { ViewModel = this, PropertyName = "MyProp" });
}
}
And in the viewModel that is interested in the event you might do something like this:
public class ViewModel2
{
public ViewModel2()
{
Messenger.Subscribe<VMChangedMessage>(handleMessage);
}
private void handleMessage(VMChangedMessage msg)
{
// Do something with the information here...
}
}
Notice that the two viewModels never reference each other. They are now loosely-coupled.
There are a number of pre-existing implementations already available and it isn't difficult to create your own (the messenger basically keeps a list of objects that are interested in a certain message and iterates the list when it needs to notify the interested parties). There are a few things that can be implemented differently (some implementations just pass string messages around rather than encapsulating the information in objects, and some handle the clean-up of observers automatically).
I would recommend using Josh Smiths (excellent) MVVM Foundation which includes a messenger class. It's also open source so you can see how it works.
There is no clear constraint about what PropertyName should contains in PropertyChangedEventArgs.
See Subscribe to INotifyPropertyChanged for nested (child) objects.
Here is an example :
class A : BaseObjectImplementingINotifyPropertyChanged {
private string m_name;
public string Name {
get { return m_name; }
set {
if(m_name != value) {
m_name = value;
RaisePropertyChanged("Name");
}
}
}
}
class B : BaseObjectImplementingINotifyPropertyChanged {
private A m_a;
public A A {
get { return m_a; }
set {
if(m_a != value) {
if(m_a != null) m_a.PropertyChanged -= OnAPropertyChanged;
m_a = value;
if(m_a != null) m_a.PropertyChanged += OnAPropertyChanged;
RaisePropertyChanged("A");
}
}
}
private void OnAPropertyChanged(object sender, PropertyChangedEventArgs e) {
RaisePropertyChanged("A." + e.PropertyName);
}
}
B b = new B();
b.PropertyChanged += (s, e) => { Console.WriteLine(e.PropertyName); };
b.A.Name = "Blah"; // Will print "A.Name"
The best thing to do here is to separate the idea of a Model and a ViewModel.
By having a ViewModel object that is flatter than the Model you can avoid this scenario. Using an automatic mapping tool like Automapper then allows you to map the Model to the ViewModel and vice versa.
https://github.com/AutoMapper/AutoMapper/wiki/Flattening
class MyDatViewModel : INotifyPropertyChanged
{
public string Str
{
// ... Get Set
}
public int NestedObjNum
{
// ... Get set
}
}
// Configure AutoMapper
Mapper.CreateMap<MyDat, MyDatViewModel>();
// Perform mapping
MyDatViewModel viewModel = Mapper.Map<MyDat, MyDatViewModel>(someData);

Writing a maintainable commit method

I have a ViewModel that encapsulates some properties that are being edited in an options dialog. I can't actually save them to the settings until they hit the Ok button, which will end up calling Commit on this particular ViewModel.
A single property in my ViewModel looks like this:
public bool SomeProperty
{
get
{
return m_SomeProperty;
}
set
{
if (m_SomeProperty != value)
{
m_SomeProperty = value;
NotifyPropertyChanged("SomeProperty");
}
}
}
private bool m_SomeProperty = Properties.Settings.Default.SomeProperty;
So the normal implementation for Commit would be to do this:
public void Commit()
{
Properties.Settings.Default.SomeProperty = m_SomeProperty;
// Add other properties here...
}
This isn't so bad, but the reason I don't like this is that if you add a new property, you have to add code for it in two places. I try to avoid that when possible.
At first I thought I could declare a private event called OnCommit and have the Commit method raise that event, and have the code for each property add an event handler for the event and do the writing to the settings there, but I don't know how to do that without adding the event handlers in the constructor anyway, which doesn't help the situation.
Any ideas? Does anyone have an elegant way to do what I'm trying to do?
EDIT: Thanks to sixlettervariables for the answer. I took that idea and incorporated it into SoapBox Core and open sourced the result. Check out the Options Dialog to see how it works.
Perhaps maintain a list of Actions to execute?
private List<Action> commitActions = new List<Action>();
public bool SomeProperty
{
get
{
return m_SomeProperty;
}
set
{
if (m_SomeProperty != value)
{
m_SomeProperty = value;
lock (commitActions)
{
commitActions.Add(
() => Properties.Settings.Default.SomeProperty = value);
}
NotifyPropertyChanged("SomeProperty");
}
}
}
Then update your Commit code to loop through the actions.
public void Commit()
{
List<Action> commits;
lock (commitActions)
{
commits = new List<Action>(commitActions);
commitActions.Clear();
}
foreach (var commit in commits)
{
commit();
}
}
Could you use reflection to determine which properties your class has and iterate through them?

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