Suppose I'm implementing an MVP pattern and I have a view interface as such:
interface IView {
string SuperRadString { set; }
}
There's no reason for the presenter to ever need to retrieve this string from the view, so can I safely ignore this error?
Well, yes...
However, semantically it would make more sense to have a method for setting the value than a "black hole property".
Related
I've been trying to find the correct approach for this problem I got, using Prism with Xamarin Forms:
I've a model class, Customer, that contains another class, Address as a property. In my view, I show fields from both objects. I would like to have a "save" button, that only gets enabled after you've made some changes to those models.
Now, the button is bound to a Command, with the corresponding CanSave() function, as is normal with DelegateCommands. I'm trying to find an approach where I can end up with a single IsDirty property on my view model, that gets to "true" after any changed to the underlying models.
The MVVM approach
First thing I thought was the "purist" mvvm approach. A "flat" view model, with properties for each visual element, implemented as a Prism BindableObject, where each getter/setter gets/sets values from/to the underlying model classes.
That failed though, since SetProperty<> has a ref parameter, where I can't use properties from my models.
The over-engineered approach [?]
Second thing I thought was that, if my inner models were observables themselves, I could listen for changes from all of them, throughout the tree. Which opens up a whole new world of issues. Do I register property change listeners in my View model ? Do I make inner models observables, and have the parents listen for change events on their children and propagate that ?
Won't that observable models approach quickly become event handler hell ?
The simplest thing
And last, the simplest thing possible. I have a flat observable ViewModel, that only reads/writes values to/from the actual inner hierarchical model upon read & save
What do you guys think ?
Maybe I didn't understand your question right, but I'm wondering why you limit yourself to such a small helper function like SetProperty. It has 4 Lines of code. All it does is checking for equality, setting a value and raising an event.
You could easily create another helper function like this.
MyBindableBase
protected virtual bool SetProperty<T>(Func<T> get, Action<T> set, T value, [CallerMemberName] string propertyName = null)
{
if (object.Equals(get(), value)) return false;
set(value);
OnPropertyChanged(propertyName);
return true;
}
Model
class Model
{
public string Property { get; set; }
}
ViewModel
class ViewModel : BindableBase
{
private Model Model { get; set; }
public string Property
{
get { return Model.Property; }
set { SetProperty(() => Model.Property, x => Model.Property = x, value); }
}
}
I think you can shorten the usage, if you introduce some naming rules for the mapping and/or use reflections.
Well, in the end I went for option 3, the simplest thing I could do.
I was leaning towards returning properties from my model, which would be easy, and using the nullable [?.] syntax it would be null-safe too, but I found that at times I'll have to wrap the actual model properties with something that is more UI-friendly, exposing more/different properties than my actual DB model classes.
So, I went for that, until some other complexity forces me to change my mind again :)
Thanks a lot #Sven-Michael Stübe and #adminSoftDK for the help
I noticed that in v3, MvvmCross removed the generic declaration <TViewModel> on MvxTouchViewController and renamed it to MvxViewController.
This means the ViewModel property is typed as a generic interface of IMvxViewModel rather than the specific TViewModel.
If I need to access the TViewModel in my view controller, is there a convenient way of getting the ViewModel already cast to the specific instance type for this View? Or do I have to cast it myself every time?
The previous Generic-based MvvmCross Views were removed from MvvmCross mainly because of the threat of 'Heizenbugs' in the objective-C based platforms.
For what little anyone knows about Heizenbugs, see http://forums.xamarin.com/discussion/771/exporting-generic-type-to-objc-supported
I don't believe I ever saw an Heizenbug, but Xamarin were very clear in their advice to avoid them at all costs - for example, they twice changed the compiler to issue errors for our generics. Indeed, on .Mac such generic code remains an error today, while on .iOS it's just a very scary warning.
Added to this, we did also encounter some issues with Xaml based platforms when inheriting from Generic base classes - although these were mainly resolved (e.g. XamlParseException when I inherit a Page from a Generic base class)
(Aside - to allow some backwards compatibility, WindowsPhone does still have some limited generic View support, but this is marked as Obsolete and I do regret allowing this to live on...)
The good news is that, in my experience, the majority of Views do not need to know their ViewModel type - instead, the majority of Views can be built with 'pure bindings' without declaring a typed ViewModel.
For those remaining Views which do need to know their ViewModel type, then a simple added property quickly adds this - e.g.:
protected MyViewModel MyViewModel
{
get { return (MyViewModel)base.ViewModel; }
/* set is optional - not typically needed
set { base.ViewModel = value; }
*/
}
Alternatively you can probably write an extension method for this if you want to - e.g. something like:
public static TViewModel TypedViewModel<TViewModel>(this IMvxView view) where TViewModel : class, IMvxViewModel
{
return view.ViewModel as TViewModel;
}
Very alternatively....
.... If you are not scared of ghosts, goblins or Heizenbugs....
One way to add the TypedViewModel property to all of your views would be to add generics back into your view hierarchy - this is easy for you to do - e.g. in Android adding
public class BaseActivity<TViewModel> : MvxActivity
where TViewModel : class, IMvxViewModel
{
protected TViewModel TypedViewModel
{
get { return (TViewModel)base.ViewModel; }
/* set is optional - not typically needed
set { base.ViewModel = value; }
*/
}
}
This should work fine for you... but if you hit an Heizenbug, then I don't think anyone will be able to assist you. Xamarin have been very clear in recommending against this pattern - especially on the objC based platforms.
As of 3.5, generic based views are supported again as apparently the underlying Xamarin issue has been fixed.
http://slodge.blogspot.co.uk/2015/01/mvvmcross-v35-pushed-to-stable.html
I got the following variable into my entity:
[DataType(DataType.Currency)]
[DisplayName("Value U$:")]
[Required(ErrorMessage = "Currency Required.")]
public decimal? CurrecyValue { get; set; }
Actually Im using this entity and I dont need this field. As soon as I post any information the ModelState becomes invalid because its required.
I know that I can use ModelState.Clear(); but, doing this I'll ignore all the other validations that I need.
Is there any way to just ignore this specific field without clearing my whole ModelState ?
Thanks !
Ugly and totally not recommended workaround:
ModelState.Remove("CurrecyValue");
Recommended solution:
Use view models. But real view models. Not some hybrids which you call view models and into into which you stick your domain entities and which you wonder how to get rid of simply because they are not adapted to the requirements of the given view. You should define a specific view model for each of your views. If you don't follow this very simple rule you will struggle a lot with ASP.NET MVC.
I started working with the MVVM pattern in a new project.
Everything is ok, but i came to the following problem.
The implementation looks like this:
I have a MainView, the main app window. In this window i have a telerik RadGroupPanel in wich I host the rest of the app views as tabs.
The rest of the viewModels does not know about this RadGroupPanel which is hosted in MainVIew.
How should i correctly add those views to the RadGroupPanel from the commands in the viewModels?
Thanks.
Have you considered injecting your view into the ViewModel using an interface to maintain separation? I know this breaks MVVM but I've successfully used this on a number of WPF projects. I call it MiVVM or Model Interface-to-View ViewModel.
The pattern is simple. Your Usercontrol should have an interface, call it IView. Then in the ViewModel you have a property with a setter of type IMyView, say
public IMyView InjectedView { set { _injectedView = value; } }
Then in the view you create a dependency property called This
public MyUserControl : IMyView
{
public static readonly DependencyProperty ThisProperty =
DependencyProperty.Register("This", typeof(IMyView), typeof(MyUserControl));
public MyUserControl()
{
SetValue(ThisProperty, this);
}
public IMyView This { get { return GetValue(ThisProperty); } set { /* do nothing */ } }
}
finally in Xaml you can inject the view directly into the ViewModel using binding
<MyUserControl This="{Binding InjectedView, Mode=OneWayToSource}"/>
Try it out! I've used this pattern many times and you get an interface to the view injected once on startup. This means you maintain separation (Viewmodel can be tested as IView can be mocked), yet you get around the lack of binding support in many third party controls. Plus, its fast. Did you know binding uses reflection?
There's a demo project showcasing this pattern on the blog link above. I'd advocate trying out the Attached Property implementation of MiVVM if you are using a third party control.
You can have the list of viewmodels that you need to add controls for in an ObservableCollection in your main window viewmodel. You can then bind the ItemsSource of the RadGroupPanel to that collection and use the ItemTemplateSelector and ContentTemplateSelector of the RadGroupPanel to select the right template to use based on the viewmodel that is bound.
I am finding it difficult understanding how best to implement 'IView' interface properties which are not simple types, and was wondering how others approach this in a Model View Presenter application.
The articles i've read are really good but none of them seem to approach more complex Views where you have List<> properties which are of an interface type which represent a class in your domain model, i.e. IPerson, or IName etc.
I will try to outline a scenario as briefly as i possibly can.
Presume i have a requirement for a View to ultimately persist a list of names, each consisting of 3 properties 'Forename', 'Surname', and 'Title'.
Typically i will have a domain model with a class called 'Name' with the 3 properties. This domain model will implement an Interface (in a separate 'Interfaces' class Library) called 'IName'.
Now in the 'Views' namespace in my 'Interaces' library i have an interface called 'IViewNames'. This is the view interface which any view which wants to ultimately persist the list of names will implement.
How to define this 'IViewNames' interface puzzles me. If i give it a property like so:
public List<IName> Names {get;set;}
then my implementing concrete view will ultimately have a complex property 'Names' which will need a 'getter' which loops through the fields on the View, somehow instantiate an instance of 'IName', set its properties, add to a List, before returning the List. The 'setter' will be just as complex, receiving a list of 'INames' and iterating through them setting fields on the View.
I feel like this is breaking one of the major goals of the MVP approach, which is being able to thoroughly test the application code without any concrete View implemntations. After all, i could easily write a presenter which looks at the 'View.Names' property and sends it on to a Service Layer, or set the 'View.Names' property when receiving a list of 'Name' objects back from the Service Layer. I could easily write a lot of tests which ensure everything works, everything except from that COMPLEX property in the View.
So my question is, how do others approach IView properties which are not simple types, but are in fact types of your domain model? (well types of interfaces which represent your domain model, as i clearly dont want a reference from my Presentation Layer to my Domain Model layer).
I'm more than certain there is a known technique to achieving this in an elegant way, which adheres to the Model View Presenter goals, more than my example approach does.
Thanks in advance for any help people.
I have not worked much on the MVP design pattern but will surely try my hands on it.
Approach1 : DataBinding
In this case you can also create individual properties in IView and bind these properties in presenter to the model properties. This way, your view will not get complicated. The experience is fast and seamless as the values from UI can be directly used in model. Changing the property value in model will reflect in UI immedietly. You may have to use NotifyPropertyChange events for this.
Approach 2 : Complex Types
You can try creating List or Tuples to store these values and use the values in the presenter. You may have to use events or actions to reflect the value from model to view and vice versa.
Please let me know if it helped you. Thanks.
I have lifted this explanation from one of the articles I am writing on my website
Presenter to View Communication
There are two styles utilised for populating the View with data from the Presenter and Model that I have used. The only difference between them is how tightly coupled you mind your View being to the Model. For the example of this, we will have the following as our Model:
public class Person
{
public int ID { get; private set; }
public int Age { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
Public Genders Gender { get; set; }
}
Method 1: Using the Model
Now our View code:
public interface IEmployeesView
{
void ClearList();
void PopulateList(IEnumerable<Person> people);
}
And finally the Presenter:
public class IEmployeesPresenter
{
public void Display()
{
_view.ClearList();
_view.PopulateList(_model.AllEmployees);
}
}
This method of population produces a link between the Model and the View; the Person object used as a parameter in PopulateList.
The advantage of this is that the concrete implementation of the IEmployeesView can decide on what to display in its list of people, picking from any or all of the properties on the Person.
Their are two disadvantages of this method. The first is that there is nothing stopping the View from calling methods on the Person, which makes it easy for lazy code to slip in. The second is that if the model were to change from a List<Person> to a List<Dog> for instance, not only would the Model and the Presenter need to change, but so the View would too.
Method 2: Using Generic Types
The other method population relies on using Tuple<...>, KeyValuePair<,> and custom classes and structs:
Now our View code:
public interface IEmployeesView
{
void ClearList();
void PopulateList(IEnumerable<Tuple<int, String> names);
}
And finally the Presenter:
public class IEmployeesPresenter
{
public void Display()
{
var names = _model.AllEmployees.Select(x => new Tuple<int, String>(x.ID, x.FirstName + " " + x.LastName));
_view.ClearList();
_view.PopulateList(names);
}
}
The advantages of this method of population is that the Model is free to change without needing to update the View, and the View has no decisions to make on what to display. It also prevents the View from calling any extra methods on the Person, as it does not have a reference to it.
The down sides to this method, are that you loose strong typing, and discoverability - It is quite obvious what a Person is but what a Tuple<int, String> is less obvious.