I have a database that communicates with webservices with my Model (own thread) and exposes Data Objects. My UI application consists of different Views and ViewModels and Custom Controls. I'm using ServiceProvider (IServiceProvider) to access the Model and route the events to the UI thread.
Communication between the ViewModels is handeled by a Messenger.
Is this way to go?
I was also wondering what is the best way to strucutre the DataObjects
At the moment i have the DataObjects that have a hierarchy structure but does not support INotifyProperty though the children list are of type of ObservableCollection. I have no possiblity to implement notifypropertychange on the properties.
I was wondering the best way of making them MVVM friendly. Implementing a partial class and adding all the properties or commands that are necessary or wrapping all the DataObjects and keep the Model list and MVVM list in sync.
All thoughts and ideas are appreciated.
Strictly implementing MVVM means that you should create ViewModel classes that expose all the DataObjects (your Model) that will be used the View - the View should not be able to access the Model directly.
Following this, you will have full control over your ViewModel and you'll be able to implement INotifyPropertyChange events and synchronise the ViewModel with the Model on each change notification or upon specific actions.
I would agree with Bermo with a note that not many people do not strictly implement the pattern. May expose the Model objects directly and implement INotifyPropertyChanged in those objects. But below is the basic means you can use to implement what you have so far:
class PersonViewModel : INotifyPropertyChanged
{
Person p = new Person();
public string First
{
get { return p.First; }
set
{
p.First = value;
onPropertyChanged("First");
}
}
public string Last
{
get { return p.Last; }
set
{
p.Last = value;
onPropertyChanged("Last");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(string propertyName)
{
if (PropertyChanged!=null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
}
}
#endregion
}
I personally created a ViewModel class to inherit from so that I could put my INotifyPropertyChanged code there and not have to put it in repeatedly. Then my implementations simply inherit from that base class.
Related
I have tried to use MVVM Light messaging to communicate between different ViewModels, but with time it gets quite messy and hard to understand from where and where to all the messages are flying so I wanted to ask about other solution how to communicate between ViewModels using Interfaces. The provided code works well, but I am not sure if Interfaces are mended to be used this way..
So here I have defined interface and class that implements it:
public interface ISelectProject
{
event EventHandler<SelectedProjectEventArgs> MessageReceived;
void ProjectSelected(...);
}
public class SelectProject : ISelectProject
{
public event EventHandler<SelectedProjectEventArgs> MessageReceived;
public void ProjectSelected(..)
{
MessageReceived?.Invoke(this,new SelectedProjectEventArgs(...));
}
}
Afterward, I inject SelectProject class into these tree ViewModels using constructor injection(code not shown here).
Then in ViewModelA I invoke MessageReceived event and all the other ViewModels subscribe to the event.
public class ViewModelA : ViewModelBase
{
public ViewModelA(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.ProjectSelected;
}
}
public class ViewModelB : ViewModelBase
{
public ViewModelB(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.MessageReceived += (s, data) =>
{
...
};
}
}
public class ViewModelC : ViewModelBase
{
public ViewModelC(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.MessageReceived += (s, data) =>
{
...
};
}
}
My questions are:
1) Does this somehow violate MVVM practice?
2) Is it considered a good practice to communicate between ViewModels like this?
3) Does this solution introduce any risks, for example, memory leaks, etc?
Thank you!
1) Does this somehow violate MVVM pratice?
No. ISelectedProject is basically a shared service. A shared service is a class that provides functionality to several components in a decoupled way. Please refer to this link for more information and an example.
2) Is it considered a good practice to communicate between viewModels like this?
Yes, if you want to keep them decoupled from each other.
3) Does this solution introduces any risks, for example memory leaks, etc.
Using a shared service doesn't introduce any memory leaks by itself. But if your shared service exposes an event and a view model subcribes to this one without unsubscribing from it, the service will keep the view model alive.
Suppose we have a generic View model like this:
public class MyViewModel<T> : INotifyPropertyChanged where T : Class1
{
private T _objectModel;
public MyViewModel(T object)
{
_objectModel= object;
}
public event PropertyChangedEventHandler PropertyChanged;
}
When I want to bind this View Model to DataContext of my UserControl in XAML, I can not! XAML editor does not find My View Model class. How should I refer to a generic type in XAML?
<UserControl.DataContext>
<s:MyViewModel<T>/> // How should I write this here????
</UserControl.DataContext>
In the above code s is an alias for my workspace, and If I convert my generic View Model to a concrete class it works normally.
When working with XAML, you cannot instantiate a view model with a generic parameter in XAML code.
To work around this, you need to make use of inheritance, here's an example:
public abstract class ViewModel<T>
Usage:
public class MovieViewModel : ViewModel<Movie>
...
public class GenreViewModel : ViewModel<Genre>
Creating a new class for each model seems to be a bit stupid, however this simply isn't true. By making the assumption that each view model contains one model, you've pretty much set yourself up for following this pattern in all view models, as your base view model enforces this constraint.
I personally use the pattern of using a ViewModel<T> base class, where T is the model.
It's certainly a good idea to keep the logic separated from your base view model. A view model for each model is in fact a very good pattern to implement.
There is another way you can achieve what you're after, this is simply removing the generic from the view model base, consider the example:
public class ViewModel
{
public object Model { get; protected set; }
}
Now, if you populate Model with let's say a Movie, then XAML will see it as a Movie, and not an object. Now this is pretty nifty as far as your XAML side goes, however, when you start working with this model in C#, then you're going to have all sorts of problems as you'll have to cast the object to whatever type you are using. So I wouldn't recommend this at all.
Another method of getting around this would be to set the DataContext in code-behind, and if you're going to do that, then, well, only God can save you now. The main ideas around the MVVM design pattern is the separation of View logic and the Business layer (View Models), as soon as your View starts instantiating view models then that nice separation is lost.
Now saying that, there's nothing stopping you from doing this, I've said this many times before. MVVM is a design pattern, not the law, if you want to set the DataContext in code-behind, then fair enough, however it's important that you are aware of the implications.
You could create a class that inherits from your generic ViewModel and use that
public class PersonViewModel : ViewModel<Person>
XAML:
<UserControl.DataContext>
<s:PersonViewModel/>
</UserControl.DataContext>
You're not capable of setting a generic viewmodel in XAML because XAML requires known types at compile time.
Dependency injection is your best bet
public class MyControl : UserControl{
public MyControl(Object viewModel){
this.DataContext = viewModel;
}
}
If your ViewModel is derived from a base class, let's say NonGenericViewModel then you can assign in code behind an object of type NonGenericViewModel to the DataContext. Using this way you still have the benefits of generics and the data binding will also work because the bindings will be made during runtime, no matter what type of object you assign to DataContext as long as it has properties, collections, etc required by your xaml controls.
BaseViewModel<T> : NonGenericViewModel { ... }
NonGenericViewModel : INotifyPropertyChanged { ... }
And in code behind, in the ctor of your xaml.cs:
NonGenericViewModel nonGenVM = new BaseViewModel<person>();
this.DataContext = nonGenVM;
Even this is correct and working:
this.DataContext = new BaseViewModel<Person>();
It depends if you need or not the class NonGenericViewModel in other places.
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.
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 .
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.