Use model classes or setter properties with MVP - c#

I'm creating my application using setter properties, like
public interface IUserRegistrationView
{
string DisplayName { set; }
string EmailAddress { set; }
}
But I'm not sure if this is a good way to do...
Maybe I should create a Model property on the Presenter class?
What do you suggest?
thanks!

What you're doing will get the job done, but the set-only properties are a smell. Your setters, without getters, are essentially methods disguised as properties, which works but doesn't make much sense.
First, since the view has no reason what so ever of knowing anything at all about the presenter, there's no reason for it to create the presenter and inject itself to it. Instead, create the concrete view at a composition root, then the concrete presenter with the view constructor-injected into it. The presenter can then listen to events defined in the view interface so that presenter and view are as loosely coupled as possible.
Second, I would change the setter properties to SetDisplayName and SetEmailAddress methods, but only if the view can be updated by the presenter after shown and not just displaying static data. Otherwise I'd remove them completely. Remember that likely YAGNI.
Third, my primary way of conveying the initial data to display in the view would be like this, through the view's Show method:
public class UserRegistrationInfo
{
string DisplayName { get; set; }
string EmailAddress { get; set; }
}
public interface IUserRegistrationView
{
void SetDisplayName(string name);
void SetEmailAddress(string name);
// ... events for the presenter to hook into.
void Show(UserRegistrationInfo info);
}

If you are going to use this interface as in general way and others classes can use this then its better way to do.If you are specifically going to create interface then it's not a good way make property in presenter class.
As per this IUserRegistrationView i would suggest make these properties in your Business logic layer and set those properties from presenter layer .

Related

WPF MVVM - Accessing properties of other ViewModels using delegates

I have a MainViewModel, which features PersonViewModel and a HouseViewModel as properties. HouseViewModel has the property GetRooms. What is the best way to access this property from the PersonViewModel?
My solution at the minute is to pass through an instance of MainViewModel to PersonViewModel, then I can call MainViewModel.HouseViewModel.GetRooms. However, this seems a little wasteful.
I am happy to pass a function as a delegate, but I can't seem to do this with a Property. I have searched for an example of this and only come up with overly complicated techniques. I'm assuming there must be a simple way of doing this, as it seems like a common problem. Can anyone point out a strong example?
Or is there another, alternative method that I haven't considered?
If a method has to be shared across two viewmodel, it should be defined in base viewmodel or a service. The best way is a common Service class should hold all common methods like GetRooms, CheckIn, CheckOut, etc. And this service should be provided to every viewmodel using Dependency Injection.
public class HomeViewModel
{
public HomeViewModel(IRoomService roomservice)
{
}
}
public class PersonViewModel
{
public PersonViewModel(IRoomService roomservice)
{
}
}

Including library functions into WPF design paradigm

Given a basic C# library, how do I implement functions of this library into my WPF application to handle appropriately the concepts of Binding and Commands?
I mean, need I write some own wrappers for these library classes in order to implement interfaces such as ICommand or should this be done directly in the library itself?
Some code to get my question more comprehensible:
From the library:
public class Item
{
public string Name { get; set; }
public void DoSomething() { throw new NotImplementedException; }
}
I want to implement the function DoSomething() in my XAML markup without any line of code in that .cs file since that is, from what I've read, the best practice.
(Assuming that an instance of Item is bound to the control)
<Button Command="{Binding DoSomething}"/>
Well, in order to do so, I need to implement the interface ICommand and create a command, but that is, as stated above, unclear to me since I'm using a library here.
Should I write my own Wrapper for the Item class of the API and implement the ICommand interface or is there any other way to archieve this? I've written the library by myself so changes are possible. I'm just not entirely sure about changing the library because if I do so, it is (possibly) bound to WPF.
Hi there if anything your ViewModel should handle any requests on your Model that's it's sole purpose, to get these things to work you need ICommand and if you want some more info here is link with a tutorial on RoutedCommands. If you have your Model and ViewModel defined then you can easily assign tasks to the particular Model through its VM.
P.S. I think you could treat your library as a Model and write a "wrapper" ViewModel to handle operations on it. HTH
UPDATE
Consider following:
class libClass
{
void method()
{
//do something here
}
}
code above would be your model and if you want it to be more readable you could do it this way
class libModel
{
private libClass _libClass;
public libClass LibClass { get; set; }
}
Note
You could implement INotfiyPropertyChanged in your Model to handle any changes if needed of course.
now in your VM how you use the Model
class ViewModel
{
private libModel _libModel;
public libModel LibModel { get; set; }
//after you set up your RoutedCommands
//I declare method within my VM to handle the RoutedCommands don't know
//if it works when you use Property Method
void VMMethod()
{
//use VM's property to invoke desired method from your lib
}
}
and voila! ready "wrapper" for your class with implementation in your VM.
Tip
If you want to know how to do the RoutedCommands here is a link to a tutorial.

Is it possible to customize access modifiers behaviour?

I have a winform application made up of two assemblies : a business layer and a front-end layer. Each usercontrol (front-end layer) relates to a class of the business layer, i.e. CustomerUserControl uses the Customer class.
Editable properties, i.e. Customer.Name, have public setters so that their values can be modified through front-end controls.
My question is : is it possible to change the setter accessibility of a property to make it more or less restrictive only for specific classes. In my example, the Customer.Name setter would be internal, that is not accessible by front-end controls but accessible for its corresponding control CustomerUserControl. Or else, the setter would be public but not accessible to controls other than CustomerUserControl.
Is it possible to achieve such customized access rights ?
I would use the internal modifier for the setter. This makes it only accessible inside the assembly. If the CustomerUserControl is in another assembly then you can use the InternalsVisibleToAttribute
[assembly: InternalsVisibleTo("assembly name")]
EDIT: You are right. Here is another possibility:
Declare an interface that would be implemented by controls that are allowed to set names:
public interface ICustomerNameProvider
{
string CustomerName { get; }
}
In Customer add a method:
public void SetName(ICustomerNameProvider customerNameProvider)
{
this.Name = customerNameProvider.CustomerName;
}
The CustomerUserControl would call it like this:
cust.SetName(this);
Of cause this is not absolutely fool proof, but accidentally passing the wrong control would become impossible.
As far as I know, there's no way to apply what you're asking for directly to a property setter, since it doesn't know where the call initiated from. However, you could cobble something together using mutator methods:
public class Customer
{
...
public string Name
{
get;
private set;
}
public void SetName(string callingControlName, string newName)
{
// you'd use TypeOf the same way to pass in callingControlName
if(TypeOf(this).Name + "UserControl" == callingControlName)
this.Name = newName;
}
...
}
Note that this is ridiculously tightly coupled and poor design practice, but it ought to do what you want, provided you strictly adhere to the naming conventions outlined in the question (Customer matches 1:1 with CustomerUserControl). As an aside, I didn't just statically compare callingControlName to "CustomerUserControl" in order to gain a slight improvement in maintainability, in case you wanted to do something like rename the CustomerUserControl class. Also important to note is the fact that this is easily defeasible by calling Customer.SetName("CustomerUserControl","badName"). Hopefully you aren't exposing this to coders who would do things like that, but it is entirely possible.
The real issue here is that your business layer shouldn't be dependent on your presentation layer. Why would you need to restrict set access to a specific UserControl? If you have a genuine need (and I can't think of one) that a business property's set only be accessible from a certain UI class, then some significant redesigning of your application is called for.
You can limit the scope of get or set accessors like this:
//private set accessor - this is what you're looking for
public int SomeProperty { get; private set; }
//private get accessor
public int SomeOtherProperty { private get; set; }

Extending WPF application

I've got a WPF MVVM application. One of my views has a user control that needs to be customizable for each installation. It's basically a sketch of the customers installation with some labels etc. bound to a viewmodel.
Now my problem is that this user control is different on each site/installation. One approach is to load the xaml from a file/database runtime using a xaml reader. This works but since my viewmodel is generic I have to bind to methods instead of properties and I can't load a xaml with objectdataprovider.
Currently I'm trying to see if MEF can be used so that I can create the user control as a plug-in. So what I'm looking for now is this:
how can I define a user control with view/view model that exports a contract for MEF
How can my parent view (in my wpf app) load the imported user control
Any tips are appreciated, or maybe someone has a different approach?
I suggest you look into Prism in combination with MEF. It has a notion of Modules (plug-ins in your case) and Regions (mechanism of dynamically loading views).
You will be able to export a view using a simple attribute:
[ViewExport(RegionName = RegionNames.MyRegion)]
public partial class MyView : UserControl {
public MyView() {
this.InitializeComponent();
}
[Import]
public MyViewModel ViewModel {
set { DataContext = value; }
}
}
[Export]
public class MyViewModel : ViewModelBase
[
...
}
And in your main application XAML you will be able to import the plugin's views like this:
<ContentControl Regions:RegionManager.RegionName="{x:Static Infrastructure:RegionNames.MyRegion}"/>
One thing I'd consider is the design where you need to install a custom View for each installation. Instead, I'd look to make that View more generic. This will make your design more simple in the long run. Plus, you are setting up for a maintenance nightmare with a different installation for every installed base.
It's a little difficult to tell from your description, but it sounds like the View is a collection of some kind of an object (some kind of drawing with a label or something). Therefore, I'd treat it as such.
I'd create a base abstract class that describes what every object that your View could show. Since I don't have more information, I'll call this thing a "DrawingObject" for lack of a better term. This class would hold all information common to all objects in your View. Note that ObservableItem is a class that implements INotifyPropertyChanged, and SetProperty sets the value in that base class and raises PropertyChanged.
abstract class DrawingObject : ObservableItem
{
Point mPosition;
public Point Position
{
get { return mPosition; }
set { SetProperty("Position", ref mPosition, value); }
}
String mLabelText;
public String LabelText
{
get { return mLabelText; }
set { SetProperty("LabelText", ref mLabelText, value); }
}
}
Then, derive more custom objects from that base class:
class Counter : DrawingObject
{
public Counter() : base()
{
}
}
Your ViewModel would then just have a collection of these objects, using the base class. The set may be private, because you will probably get the objects from someplace in the constructor (i.e. the database, or a flat file, or...)
class ViewModel : ObservableItem
{
public ViewModel() : base()
{
// Call something to populate DrawingObjects property
PopulateDrawingObjects();
}
ObservableCollection<DrawingObject> mDrawingObjects =
new ObservableCollection<DrawingObject>();
public ObservableCollection<DrawingObject> DrawingObjects
{
get { return mDrawingObjects; }
private set { mDrawingObjects = value; }
}
}
Then, your View would bind to this collection and draw them appropriately (I'll leave that as an exercise for the implementer).
One extension that I didn't show is that the DrawingObject may need to implement the appropriate serialization functionality.
Obviously, this is a rough sketch of the design, and may have a couple of errors (I did it from my head), but hopefully it's enough to go on.

C# add custom attributes for a parent's property in an inherited class

I'm displaying Business Object in generic DataGrids, and I want to set the column header through a custom attribute, like:
class TestBo
{
[Header("NoDisp")]
public int ID {get; set;}
[Header("Object's name")]
public String Name { get; set; }
}
So far, so good, but I'd also want to separate my display from my data, by inheritance:
class TestBO
{
public int ID {get; set;}
public String Name { get; set; }
}
class TestPresentationBO : TestBO
{
//Question: how to simply set the Header attribute on the different properties?
}
I see a solution via reflection with a SetCustomAttribute in the Child constructor, but it will be cumbersome, so is there a simple and elegant trick for this problem?
Please prevent me from breaking the data/presentation separation ;o)
Question: how to simply set the Header attribute on the different properties?
There is no way to set an attribute on an inherited member the way you have suggested, since attributes are specific to a type. SetCustomAttribute won't help you - it's only any good when you construct new types at runtime. Once an attribute has been compiled in you cannot change it at runtime, since it's part of the metadata.
If you want to maintain the separation you will have to find another way.
(You could make the properties virtual, override them in the Presentation class and add attributes on the overrides, but this looks dodgy and doesn't really separate anything - you end up with a complete TestBO class in your TestPresentationBO anyway...)
Make the properties in TestBo virtual and override them in TestPresentationBO. That way you can add the attributes.
Just thinking, can't you solve this with partial classes and the MetadatatypeAttribute? MVC2 uses this pattern for Model validation.
You can do it like WCF RIA Services. Add an attribute to TestBO, like [Presentation] taking a type as parameter. This new type will redefine the properties, but with the presentation attributes.
At run-time, you have to get the identity of the new type and get the custom attributes of its properties.
Or forget about the attribute and have a dictionary mapping the BO with the presentation BO class. This presentation BO class does the same thing as above, i.e. redefine properties with custom attributes.
the presentation BO class is never instantiated, it is simply reflected upon to get presentation info.
Are you using the MVVM (model view view-model) pattern? It seems to me, and partly from the other answers, that you can't really do this with the custom attributes like you want. But, it also seems to me that your TestPresentationBO is really just like a "View Model" for TestBO. A view model is basically a sort of wrapper or surrogate for a business or logic class--which is basically what you want. (This summary of a view model may not be 100% accurate; I'm just starting out with MVVM myself.)
You can create a TestBOViewModel to wrap TestBO, then pass the collection of TestBOViewModel to the datagrid. Of course, you can decorate the properties exposing the wrapped class with [Header("Object's name")] etc. This doesn't use inheritance, but I don't see why you'd need to use inheritance in this situation. Using a view model, does, however, cleanly separate your presentation (view) from your data (model) by using the wrapper (view model).
For more info on the MVVM pattern, I found this to be an interesting read: WPF Apps With The Model-View-ViewModel Design Pattern.
Something like this. Of course, you can add validation and other goodies in here too.
public class TestBOViewModel // extend from DependencyObject
{ // if you want to use dependency properties
private TestBO _myBO;
public TestBOViewModel(TestBO bo)
{
_myBO = bo;
}
[Header("NoDisp")]
public int ID
{
get { return _myBO.ID; }
set { _myBO.ID = value; }
}
}
For C# 6.0 you can easily hide inherited members and introduce your own attributes. This might, however, hide any attributes on the original property. Also this simplified syntax makes the property read-only, so you might need to pipe the get/set yourself.
public class User
{
public string Login { get; set; }
}
public class UserDetail : User
{
[Display(Name = "Login:")]
public new string Login => base.Login;
}

Categories