Passing Model Between Silverlight Views - silverlight

Since the basic navigation mechanism in Silverlight only allows passing arguments in a querystring, when we want to pass complex data (e.g models) between our views, we use the IEventAggregator's pub\sub mechanism.
But the question is - is there a better way to pass complex information between views?
What are the cons of using the IEventAggregator for this?

This is why I switched to a ViewModel first approach. Views really aren't configurable nor should they really be passing ViewModels around. It made a lot more sense to me for a ViewModel to load another ViewModel like:
Show.Screen<OrderDetailsViewModel>(vm => vm.OrderId = orderId);
This is from the Build your own mvvm framework talk and is also similar to how Caliburn Micro works.

I can't tell you why IEventAggregator is bad, maybe it's not so intuitive? When you look at your app - you want to see what's going on and doing events with some data doesn't seem to be good. Event is event. You can share some data via Region's context in PRISM.
I'm solving same kind of issues using MEF. So, you can define something like
[Export]
public class MyModelService
{
// Code here whatever shared data you want
}
public class MyViewModel
{
// Import this shared ModelService
[Import]
public MyModelService ModelService
}
So, if you had some data in ModelService - by default MEF will compose it just once (effectively making it shared) and every time you import it inside ViewModel this instance will be there. Then you can use Events originated from ModelService to tell components when data updated, etc.

I'm currently using a Session idea, like in ASP.NET. I've defined a static object named SilverlightSession and add a Values property of type Dictionary. Then I just add to the values dictionary or update it and cast it
public static class SilverlightSession
{
public static Dictionary<string, object> Values { get; private set; }
}
in the app.xaml.cs startup:
SilverlightSession.Values = new Dictionary<string, object>();
Then you can have your models in "session" until the application closes.

Related

Correct way to handle commands that rely on multiple view models

I'm relatively new to WPF and MVVM and i am trying to understand how to use commands correctly when they have dependencies in more than 1 view model.
A couple of examples:
In my current application i have a RelayCommand which causes a save action to occur in a couple of different view models (they write a couple of different files). Currently i am handling this using a the mvvmlight messenger to send a message to those view models to get them to do the save which i think is the correct way to do it as it avoids having to provide some kind of delegate or event to/on those view models.
I have a RelayCommand in a view model that has a CanExecute method which relies on the state of 2 other view models. I've currently handled this via the mvvmlight messenger as well by having changes in the view models the CanExecute method depends on message that their state is now valid for the operation. This seems messy but the only alternative i could think of was to use a delegate or event effectively weaving the view models together which i believe i should be avoiding.
Is there some generally accepted way to deal with this which i am missing?
In general your view model layer should have a 1:1 relationship with your view, there should be no good reason for a "Save" function to exist in a view model which is then called by another view model.
What it sounds like you should be doing is putting that logic into a service i.e. something like this:
public interface ISerializationService
{
void Save(SomeData data);
}
Then you need an implementation for this service that does the actual work:
public class SerializationService : ISerializationService
{
void Save(SomeData data)
{
// actual save happens here
}
}
Your view models should then contain properties that point to instances of these services:
public class MyViewModel : ViewModelBase
{
[Inject]
public ISerializationService SerializationService { get; set; }
// called when the user clicks a button or something
private void ButtonClickCommand()
{
this.SerializationService.Save(this.SomeData);
}
}
The only question remaining is "What sets the value of SerializationService?", and for that you need a dependency injection framework. There are plenty out there, MVVMLight installs one itself, but Ninject is the de-facto standard. When implemented properly the injection framework will create all view models for you and then "inject" the dependencies, i.e. your SerializationService property, of type ISerializationService, will be initialized with an instance of your SerializationService class (which in a case like this will also be configured to be a singleton).
Dependency Injection takes a bit of work to get your head around but once you start using it you'll never look back. It facilitates complete separation-of-concerns whilst alleviating the need to pass pointers to everything all up and down your architectural hierarchy.

Access properties from one view model in another

My WPF application follows the MVVM pattern. There are three views:
MainWindow
LoginView
ProjectsView
LoginView and ProjectsView are user controls imported by the MainWindow. Both views have their view model assigned. LoginViewModel defines a property ProjectList which is set by calling a webservice. Now LoginViewModel needs access to the ProjectList property and others.
I am aware that one solution might be a redesign so that there is only one view and one view model. I would do that as a backup solution but I would favor not to do so.
How should this be done? Should I use some kind of EventAggregator like in Prism? Or are there other ways to do this?
So if i understood clearly, ProjectList property should be accessed from both 'LoginViewModel' and 'ProjectsViewModel'. I'd try to implement it in the 'MainViewModel' so child viewmodels can access it in a natural way.
An IEventAggregator is like a box in which you can add events, or find and subscribe to one, so i would say it's not what you need.
Anyway, you could register your custom interface (box type) in the UnitySingleton.Container, which would expose ProjectList for it to be accessible everywhere. This approach makes a lot of sense when modules, which are separate assemblies, need to communicate whith each other.
If this is overkill or not in your case is something you should decide, i'd personally go with the 'put it in the mainviewmodel' option.
-- Sample -- (not tested)
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
LoginVM = new LoginViewModel(this);
ProjectsVM = new ProjectsViewModel(this);
RetrieveProjectList();
}
public LoginViewModel LoginVM { get; private set; }
public ProjectsViewModel ProjectsVM { get; private set; }
public object ProjectList { get; private set; }
private void RetrieveProjectList()
{
ProjectList = ....
}
}
It's pretty simple as you see, LoginVM and ProjectsVM will hold a reference to the MainViewModel that created them, therefore giving them access to ProjectList.
How should this be done? Should I use some kind of EventAggregator
like in Prism? Or are there other ways to do this?
Here are a few ideas:
You can create a view-model class that both view-models
inherit from. This base class will contain the shared properties.
Create a static class that contains the shared properties.
Using dependency injection, create a class that contains the
properties, register it as a singleton in your container and inject
it into your view-model's ctors.
Also, I believe that the EventAggregator is best suited for communicating between modules/assemblies. In your example, it seems like everything is in the same assembly.

Custom property injection in Castle Windsor for Windows Forms

I have a Windows Forms application which makes use of an MVP pattern. Each view is a WinForms user control and is backed by a presenter which handles non-UI concerns. The application makes use of Castle Windsor, and all views presenters and many other components are resolved via the Windsor Container.
What I would like to be able to do is customise property injection for the user control views. My views don't make a whole lot of use of property injection, but it is occasionally very useful and works well. The problem is, my user controls often contain nested controls, which in turn can contain other nested controls, and property injection is not going to work for these nested controls, because they were not directly resolved via the container.
What I would like to do is to configure property injection for components that inherit from the SWF Control class. In addition to finding properties on the component, I would like to also find properties on nested controls (in the Controls) collection and inject into these nested properties as well.
I know that Castle Windsor is extremely flexible and configurable so this may be possible. I need a bit of a nudge in the right direction though. Is this possible? Has anyone tried to do something similar?
If I have understood your question correctly I think that the only way to achieve what you want is by some sort of poor man's dependency injection because the way the winforms designer generates a method that constructs the various sub-controls you speak of makes it decidedly uncondusive to IoC.
I am not sure you will be able to do property injection but you can utilise the constructor, here is a hair-brained scheme I have just concocted ...
Firstly, create some way to access your windsor container - something like this would probably do the trick:
public static class MyContainer
{
private static readonly IWindsorContainer _container = Bootstrap();
// I did it like this so that there is no explicit dependency
// on Windsor - this would be the only place you need to change
// if you want an alternate container (how much you care about
// that is up to you)
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
private static IWindsorContainer Bootstrap()
{
var container = new WindsorContainer();
container.Install(FromAssembly.This());
// ... whatever else you need to do here
return container;
}
}
Secondly, in the inner controls, where you want some properties injected do something like this (I went for the good ol' ILogger as an example of something you may want injected):
public partial class MyFancyControl : UserControl
{
// Constructor to keep the winforms designer happy
public MyFancyControl()
: this (MyContainer.Resolve<ILogger>())
{
// Intentionally always blank as this
// is an un-unit-testable method
}
// Constructor that does the actual work
public MyFancyControl(ILogger logger)
{
InitializeComponent();
Logger = logger;
}
public ILogger Logger { get; private set; }
}
Note: using the logger raises one of the couple of obvious smells in this - sometimes you don't register such a component with the container at all (usually you have a null logger) so you may need to hook up some sort of mechanism for that but I leave that up to you if you need it or not.

Dynamically generating ViewModel for tooltips in WPF MVVM

I have a list of items representing packages in an MVVM control.
When you hover over the tooltip it needs to go to the database for additional information, lets just call it 'PackageDetails' for simplicity. I know how to handle the database loading with a ViewModel class but I'm having trouble figuring out when to instantiate it.
Approach 1) Have a 'lazy-load' property in the 'Package' object so when the tooltip is triggered the viewmodel will be created and immediately access the database.
This approach isn't ideal because each 'Package' object isn't a true viewmodel and came from WCF objects originally.
Approach 2) Use a converter as explained in this Josh Smith blog entry. His example seems to fit a converter well, but I don't think it really suits my situation well.
Approach 3) Somehow create a viewmodel in the XAML, but this seems like a bad idea.
What's a good approach to dynamically generate a viewmodel for a tooltip using MVVM
?
Binding models ( in your case the packages ) to the view only works for very simple situations where there is no more "processing" or business logic to implement.
I have experimented with a few options and in the ended up creating a VM wrapper for just about all my models. Going down this path makes having a tooltip property straight forward.
The other option that i have experimented with is to use partial classes to extend the wcf models. This works unless you are using dataannotations for validation ( wcf and dataannotations dont work together properly )
if you decide to wrap your models with a vm, then instantiating your list of VM wrappers is just one line of code using linq and lambdas
assuming you have a constructor on your VM that accepts your model as a parameter.
var listPackageVMs = new ObservableCollection<PackageVM> ( listPackageModels.Select(model=> new PackageVM(model)));
You could create a partial class to Package. I would avoid placing data access logic in an entity class, but this is the cheap and easy way.
namespace WCFServiceNamespace
{
// Since WCF generated entities are partial classes, we can inject features
public partial class Package
{
private readonly IDataAccessor _DataAccessor;
public Package()
: this(DataAccessor.Instance) // how you choose to inject a data accessor is up to you
{
}
public Package(IDataAccessor dataAccessor)
{
_DataAccessor = dataAccessor;
_ToolTip = new Lazy<string>(GetToolTip);
}
private readonly Lazy<string> _ToolTip;
public string ToolTip
{
get
{
// executes GetToolTip when the Value property of Lazy<T> is accessed
return _ToolTip.Value;
}
}
private string GetToolTip()
{
// we're assuming we can retreive the tooltip by ID, and that PackageId is defined in the generated WCF entity
return _DataAccessor.GetToolTipByPackageId(PackageId);
}
}
}

MVVM - navigating between views

I have a ListBox that is bound to a ViewModel that exposes a parameter of type ObservableCollection. I have setup an ICommand that gets fired when one of the rows in the ListBox is selected. (using method 3 in this post - it works great by the way).
Now my question (which has nothing to do with method 3 described above or the ListBox) is when my ICommand is fired and what I want to do is navigate to a different page (eg: details page), where is the logic stored (or how do I do it?).
The reason I ask is that I am not sure how to setup the command method in the ViewModel class such that it remains testable.
ps: I am using Prism and was also wondering if it provides any classes/patterns for Navigation.
Just to elaborate on the use of IEventAggregator - it gives you a simple Pub/Sub model for sending arbitrary messages between decoupled (ie neither needs to know anything about the other) parts of the application. So we can get a reference to the IEventAggregator in our ViewModel constructor (this is automatically resolved for you by the framework) ie:
private IEventAggregator eventAggregator;
public PublisherViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
Then in our selection changed handler, we can publish the event:
var changedEvt = eventAggregator.GetEvent<MyListboxChangedEvent>();
changedEvt.Publish(selectedItemId);
This relies on our custom event class MyListboxChangedEvent:
public class MyListboxChangedEvent : CompositePresentationEvent<int> {}
So finally, in the ViewModel which responds to this action, we set up a subscription to the event, and corresponding handler method:
public SubscriberViewModel(IEventAggregator eventAggregator)
{
var changedEvt = eventAggregator.GetEvent<MyListboxChangedEvent>();
changedEvt.Subscribe(OnListBoxChanged, ThreadOption.UIThread);
}
public void OnListBoxChanged(int selectionId)
{
// do whatever we need
}
Seems like a lot of glue, but it becomes a logical method for wiring the different parts of the UI together, and it becomes second nature pretty quickly.
Have you considered using the EventAggregator to send the message that you want to show a different view. The StockTrader application included in the PRISM distribution will provide a good example of the use.

Resources