I'm am new to the .NET/c# realm and I am trying to develop a Windows Phone 8 application.
I have several pages showing lists of Objects(ListPage). All of these pages will have a filter capability, using a commom FilterPage.
What I need is to pass an object from the ListPage to the FilterPage.
I want to use MVVM (MVVM light templates). I've managed to implement almost everything using the Messaging framework. I'm using a FilterMessage that takes the object to be passed in its constructor.
The ListPage and the FilterViewModel listen to this message. The ListPage will navigate to the FilterPage and The FilterViewModel will take the Object from the message.
The ListPage is notified correctly but the FilterViewModel is not notified because the FilterViewModel is created only after the FilterPage is first shown.
Is it possible to initialize the FilterViewModel by App start?
If you think that this is not the way to go please tell me why:)
Thanks in advance.
What I do in this scenario is I'm adding the instance you want to pass around to the other page into the Session object you have under PhoneApplicationService.Current.State.
On the other side after you complete navigation you can extract the instance, and you should remove it from the State.
Pay attention that if your application goes into the background when you have instances inside the State, WP will try to serialize them.
I managed to make it work by creating the FilterViewModel instance in the ViewModelLocator constructor.I'm not sure that this is the best way to do it. Hopefully someone with more experience will share with us his thoughts.
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<FilterViewModel>();
ServiceLocator.Current.GetInstance<FilterViewModel>();
}
Related
I've been giving this some thought lately and I was hoping someone who has better knowledge of MvvmCross than myself can shed some light on this. Given the nuances between each mobile platform there are probably a few different factors that can affect this problem. But for this scenario let's assume we want the best approach for a cross platform solution.
So let's say we have a basic View and a ViewModel class setup. Here's an iOS example.
View
public partial class FirstView : MvxViewController<FirstViewModel>
{
public FirstView(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
Request = new MvxViewModelInstanceRequest(FirstViewModel.NewInstance());
base.ViewDidLoad();
}
}
View Model
public class FirstViewModel : MvxViewModel
{
public static FirstViewModel NewInstance()
{
return Mvx.IocConstruct<FirstViewModel>();
}
public FirstViewModel()
{
}
}
Now at the loading of this View or at some point just before the view is created we want to fetch some data from the web using a service that we inject using dependency injection; because the displaying of the view depends on that data. Here lies the problem.. at which point from a platform perspective and in the MvvmCross lifecycle would be the most appropriate place to call the web fetch function in the service.
With regards to platform I would assume that we should do it once the view loads. Because if the fetched data is anything other than simple data types it will be inconvenient to work with on Android, as one would have to persist the data to disk and retrieve it after the navigation, due to serialization between activities.
So assuming we called the web fetch during the view loading process. Where is the best place in the MvvmCross architecture to fire it off, that most closely follows the design paradigms. e.g. The View Model. Is there any lifecycle methods that someone could recommend to call it inside as well. Something like the Start method, called after the view model has been created.
First of all, I don't understand why you won't let the platform itself instantiate and do it's ViewModel lifecycle instead of creating a new instance of the ViewModel using Mvx.IocConstruct. That method does not invoke the ViewModel lifecycle and will not call neither Init or Start on the ViewModel.
If you let the platform do this for you, first the Init method will be called with the arguments that you set when using ShowViewModel<T>(args).
When ViewDidLoad invokes the Start method will subsequently be called.
This gives you two places to invoke the Service that you inject in the ctor of the ViewModel.
If you want more control over when to download the data, you could create some ICommand's, which you invoke on your ViewModel in any of the ViewController lifecycle methods. This could be in the ViewWillDisappear/ViewDidDisappear method, or you could fetch the data.
There are so many ways you can do this. In the end it is entirely up to you, and you can't possibly know when a user decides to change to another View. However, you can make qualified guesses and try fetch data before the user actually wants it.
There is a nice article for you to read here, by Rob Gibbens on how you could do Resilient network services. It describes how you could speculatively fetch resources based on what the user is doing, and this way have something ready for the user to see when he enters the View. This could be cached data or fresh data that you are fetching after showing the cached version.
In any case, I would suggest you stop loading your ViewModel's with Mvx.IocConstruct and let MvvmCross handle this for you in order to get lifecycle methods invoked.
My project is build on MVVM. Currently I have a list where i can select an object and add them to another list. What I want to make is a new window where this list is shown (the list with objects that are added) and edit that list in the new window (delte an item from that list).
How should I pass the data (selected object) to another window and be able to update them there?
I currently have it working in one view. In some related questions they advice MVVM light so I tried looking for that, from what I red mvvm light is mostly used to replace the notify property change. Should I use mvvm light or are there some specific patterns I could use?
Both windows will be open at the same time.
If you want to share your ViewModel between windows, you can use a ViewModelLocator. It is not specific to MvvmLight, it just creates one for you with its project template. You can implement it yourself, it is basically a container for your ViewModels. You can look here for the implementation details.
I've got to say that I'm not sure that these are the best approaches and if they are common, it's just what me and my colleagues were using in a WinRT application, so I'll be really glad if someone comes up with something better (both of these are not that clean).
I can think of two ways to pass data (without persisting it)
Pass parameters on page navigation
Have common shared class (Static or singleton class with some common data accessible from all ViewModels)
For passing on navigation:
I have this method in my Navigation service class:
public virtual void NavigateTo(Type sourcePageType, object parameter)
{
((Frame)Window.Current.Content).Navigate(sourcePageType, parameter);
}
and I use it like this in navigation commands:
Navigation.NavigateTo(typeof(PageType), someParameters);
Then you could get the values in the code behind of the navigated page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var receivedParameter = e.Parameter as TheTypeOfThePassedParameter;
}
And from there to pass them to the ViewModel, maybe there is an option to pass this without code in the code behind but I've not tried this.
Having shared class:
This is pretty much straightforward just have static class or a singleton with the desired fields.
It's a pretty long post and I shall try my best to explain the working of the application that I have developed and want your assistance in extending it for the future.
I need to design a windows based application in C# which basically monitors events from an external communication source and plots the data on a graph. The application subscribes to events from communication objects and updates the UI as and when there are data events. A graph component inside these monitoring classes will use the data inside the communication data buffers to plot the data as a line graph.
To achieve this, I have created a Factory class which will instantiate a particular monitoring class (CWindowFirst or CWindowSecond etc) based on Model information I provide (device model type).
These classes implement standard contract (IFactoryInterface) for initialization , data acquisition and cleanup operations. So at any given point of time I can instantiate a particular class and start the monitoring operation to receive the data and populate the graph in the process. So far so good, I can display the data in the form of a graph for a particular device.Also at the moment I'm destroying(disposing) the object of CWindowFirst whenever the main application chooses another window (i.e. CWindowSecond or CWindowThird).
As the saying goes in "SW development the only constant is the Change", A new requirement has come up where I need to give the user an option to Pause/Stop feature for the graph.
I should be able to Pause the graph (i.e. pause the data communication ) and go to main window play around and also should be able to open another window (CWindowSecond) play there around a bit with the graph again (should be able to pause the communication here as well). Come back to the first window CWindowFirst and resume the previously saved data communication.
Now comes the million $ question, how do I achieve or rather modify the existing design to implement the feature as described above.
I can think of the following implementation but I'm not sure if its really a pragmatic one.
On issue of Pause command I shall
Stop the communication (unsubscribe communication event) on Pause.
Save the state of the event data buffers and graph in a collection.
Serialize the complete object to a file before exit.
On return to the same form, I shall deserialize the object
Get the event data buffer from the deserialized object
Populate in the graph and enable the event handlers so that I continue to receive events from the communication layer.
Experts out there I need your assistance out here. Please guide / suggest improvements / share your idea
As HansPassant commented, separate the data (or context, or manager, whatever) from view. Singleton with context constructor injection is the best bet here IMHO.
Example by using the non-cleanest way of singleton:
public class MonitoringContext {
public static MonitoringContext CurrentContext = new MonitoringContext();
// handle generating data
// handle populating data needed for graph
// handle other action from other forms as well
}
public class FormGraph : Form{
// default constructor if you do not have access to MDI
public FormGraph(){
this.context = MonitoringContext.CurrentContext;
}
public FormGraph(MonitoringContext context){
this.context = context;
}
MonitoringContext context;
// do whatever you want with context
}
public class FormOther : Form{
// default constructor if you do not have access to MDI
public FormOther(){
this.context = MonitoringContext.CurrentContext;
}
public FormOther(MonitoringContext context){
this.context = context;
}
MonitoringContext context;
// do whatever you want with context
// any changes reflected at the FormGraph
// because of same reference and mutability
}
Of course this is suggested approach from outsider who do not know the requirement and current architecture deep down and detailed. Any adjustment should be made to fulfill the requirement.
I know there's a lot of questions on the topic and I understand how to do it but I need some help on the design of my architecture. I'm using the Simple MVVM Toolkit.
Architecture
I have a ShellVM which is the main VM for my app. It dishes out navigation and props that my main view binds to.
Then I have a ManageVM that does all the grit work for managing the client, stores, imports, exports etc. It also handles navigation of all my management views.
Then I have an ImportVM that fleshes out the importing of data.
I also have a static PageValues dictionary that stores pages and specific properties and values that should be retained when switching views. It also stores any 'global' properties that is used throughout certain VMs.
I'm using Messaging to pass data between the VMs. The validation and prompts (using dialogs) of the PageValues data is controlled in my ManageVM. I placed it here as I feel my ManageVM should handle all 'management' like setting the client and store. Setting the actual values is done by sending a message to the ShellVM that handles this.
The ShellVM handles the CRUD of the PageValues. So in other words, if any VM gets or sets a global/shell-wide property, it does so by means of messaging to the ShellVM. The ShellVM then sends the message/result back to whichever VM requested it.
Question
This feels very spaghetti-like. I've got a ManageVM that does the loading and validations on PageValues that are actually CRUD'ed in the ShellVM.
Am I on the right track or is there any other suggestion I can try to make this feel a bit cleaner?
Thanks for reading.
Edit
What I'm trying to achieve is to have a container that holds values (ie client and store) that could be accessible from multiple VMs. A bonus is to have each page's/view's values in this container too. Then on showing of the view, it will grab its values from the container and populate the view.
You said
if any VM gets or sets a global/shell-wide property, it does so by
means of messaging to the ShellVM
I propose an interface based approach instead of message passing for this purpose. ViewModels passing messages is for view models to communicate,not for setting a global state. If there is a global state of the application,it is better handled through a dedicated service, IMO.
public interface IApplicationService
{
//your applcation methods here
}
public class ApplicationService:IApplicationService
{
}
public class ManageVM
{
public ManageVM(IApplicationService){}
}
public class ShellVM
{
public ShellVM(IApplicationService){}
}
public class SomeOtherVM
{
public SomeOtherVM(IApplicationService){}
}
Yes, this does sound rather messy. You need to try and isolate areas of functionality into their own VMs so they are not dependent on one another.
One of the tricks I use to do this is to try and imagine that I suddenly need to copy a blob of functionality (say one of your pageviews) into another application. How easy would it be? Would it be a case of just copying one VM and injecting a few dependencies? Or is the VM impossibly coupled to the rest of the app?
It's a bit difficult to give advice without knowing exactly what your app is doing, but really you want each PageVM to be in charge of it's own validation, and CRUD. Or, if the data is shared between many pages, then you need to pass in some kind of repository than the PageVMs can query for data. If validation logic is specific to some data, then put it on the model itself and just leave the presentation of that validation to the VM.
For global settings, I tend to pass around a settings object rather than using messaging.
Have a read up on inversion of control, and dependency injection. These can help you to keep objects loosely coupled because you can see exactly what other things your object is depending upon by looking at the constructor. If you are passing in half the application then it can serve as a warning alarm to try and reduce the coupling.
Could someone be so kind as to explain MVVM Light's Messenger for me? I was reading a post on StackOverflow here: MVVM pass values between view models trying to get this. The documentation on MVVM Light's not that great at this point so I'm completely unsure where to go.
Say I have two ViewModels and a ViewModelLocator. I want to be able to pass parameters between all three without issue. How would I go about doing this with the messenger? Is it capable of that?
Edit: Here's my new implementation. As of now, it looks as if MessengerInstance doesn't call for a token. I'm terribly confused.
In the first ViewModel:
MessengerInstance.Send<XDocument>(SelectedDocument);
And in the second:
MessengerInstance.Register<XDocument>(this, xdoc => CopySettings(xdoc));
Could be completely wrong. Haven't gotten a chance to test it, but visual studio gets less angry with me when I do it this way. Also the MessengerInstance does register before the Message is sent.
Say I have two ViewModels and a ViewModelLocator. I want to be able to pass parameters between all three without issue. How would I go about doing this with the messenger? Is it capable of that?
That's exactly what it's for, yes.
To send a message:
MessengerInstance.Send(payload, token);
To receive a message:
MessengerInstance.Register<PayloadType>(
this, token, payload => SomeAction(payload));
There are many overloads, so without knowing exactly what you're trying to accomplish via the messenger, I won't go into all of them, but the above should cover the simple case of wanting to send and receive a message with a payload.
Note that "token" can be really anything that identifies the message. While a string is often used for this, I prefer to use an enum because it's a little safer and enables intellisense, "find usages", etc.
For example:
public enum MessengerToken
{
BrushChanged,
WidthChanged,
HeightChanged
}
Then your send/receive would be something like:
// sending view model
MessengerInstance.Send(Brushes.Red, MessengerToken.BrushChanged);
// receiving view model
// put this line in the constructor
MessengerInstance.Register<Brush>(this, token, brush => ChangeColor(brush));
public void ChangeColor(Brush brush)
{
Brush = brush;
}
[EDIT] URL to devuxer's comment below changed to:
http://blog.galasoft.ch/posts/2009/09/mvvm-light-toolkit-messenger-v2/