cleanup all items in a ViewModel when closing window - c#

I have RichBox binded to a List<String>ListName in the using of the window I add some item in this list, but after I close this window and I open it i still have the old added name, I know that the View model don't be disposed when I close window, but I use this on closing
public virtual void Cleanup()
{
this.MessengerInstance.Unregister(this);
}
but this will clean only the Messenger and let all my other items with values, I want to clear all resource in this ViewModel when I close the window
Update :
with Rudi answer I try on closing to do
SimpleIoc.Default.Unregister<ScanViewModel>();
SimpleIoc.Default.Register<ScanViewModel>();
and it work, but it seems not right to me to Unregister the VM and register it again !

You can just unregister an instance of the class than remove the entire class if you want.
Snippet from SimpleIoc.cs:
//
// Summary:
// Removes the instance corresponding to the given key from the cache. The class
// itself remains registered and can be used to create other instances.
//
// Parameters:
// key:
// The key corresponding to the instance that must be removed.
//
// Type parameters:
// TClass:
// The type of the instance to be removed.
public void Unregister<TClass>(string key) where TClass : class;
Do keep in mind to get a new instance of the class on every resolve from SimpleIoC we need to specify a unique key to it in GetInstance()
so in ViewModelLocator.cs keep a reference to the currentKey used and un-register it on the next attempt, something like:
private string _currentScanVMKey;
public ScanViewModel Scan
{
get {
if (!string.IsNullOrEmpty(_currentScanVMKey))
SimpleIoc.Default.Unregister(_currentScanVMKey);
_currentScanVMKey = Guid.NewGuid().ToString();
return ServiceLocator.Current.GetInstance<ScanViewModel>(_currentScanVMKey);
}
}
This way each time the VMLocator is queried for Scan a new VM is returned after unregistering the current VM. This approach would comply with the guidelines suggested by "Laurent Bugnion" Here and I'd take it he knows his own libraries pretty well and you're not going to go wrong doing it that way.
I remember MVVM Light's author state somewhere SimpleIoC was intended to get dev's familiar with IOC principles and let them explore it for themselves. It's great for simple project's, If you do want more and more control over your VM injections then I'd suggest looking at things like Unity in which your current situation would have been resolved pretty easily since you could just go
// _container is a UnityContainer
_container.RegisterType<ScanViewModel>(); // Defaults to new instance each time when resolved
_container.RegisterInstance<ScanViewModel>(); // Defaults to a singleton approach
You also get LifeTimeManagers and sorts that give even greater control. Yes Unity is an overhead compared to SimpleIoC, but it's what the technology can provide when needed than having to write code yourself.

I guess this would do it:
SimpleIoc.Default.Unregister<ViewModelName>();
edit: how about this
public ViewModelName MyViewModel
{
get
{
ViewModelName vm = ServiceLocator.Current.GetInstance<ViewModelName>();
SimpleIoc.Default.Unregister<ViewModelName>();
//or SimpleIoc.Default.Unregister<ViewModelName>(MyViewModel);
return vm;
}
}

Related

Old ViewModels catch events

I am making a Winforms program, using and MVVM-like pattern. All my data is connected to a SessionModel which is passed to all ViewModels (I know this probably isn't the best way to do things, but thats what I got).
My issue is this: Inside a ViewModel I have an event listener, which connects an event to a method, like this:
// Base constructor
public MyViewModel(SessionModel session)
{
this.session = session;
MyUserControl.MyEvent_OnActivate += AddItem;
}
// This method should be called, whenever the event is invoked
private void AddItem()
{
session.Items.AddItem();
}
A new instance of the ViewModel is generated each time the corresponding View is shown. And here arises my problem. Because everything is fine the first time I load the View and ViewModel. But the second time I visit it, the first instance still exists (although not referenced anywhere) and thereby picks up the event as well. The result is that the method AddItem() is called twice (once from each instance of the ViewModel. If I navigate to the View once again, it would be called three time, and so on.
My Viewand ViewModel is loaded from the MainForm like this:
// When called, this method loads the view and view model
private void ShowMyView()
{
MyViewModel viewModel = new MyViewModel(session);
MyView view = new MyView(viewModel);
ShowContent(view);
}
// Clears content panel and shows new view
private void ShowContent(UserControl view)
{
while (pnlContent.Controls.Count > 0)
{
pnlContent.Controls[0].Dispose();
}
pnlContent.Controls.Add(view);
}
Is there some clever way of clearing old instances of view models, since the garbage collection apparently isn't fast enough?
although not referenced anywhere...
Event subscriptions do keep the subscribers to be referenced. The old viewmodel should unsubscribe from MyUserControl.MyEvent_OnActivate whenever a new one is initialized. Make your ViewModel disposable and perform the cleanup in the Dispose method.
I found a solution, by getting rid of the event and simply listening directly to the delegate, as described in this post.
The code then looks like this:
public class MyUserControl
{
internal delegate void MyDelegate();
(...)
}
public class MyViewModel
{
public MyVieWModel(SessionModel session)
{
this.session = session;
MyUserControl.MyDelegate = AddItem;
}
public void AddItem()
{
(...)
}
}
Your problem that MyControl still keeping references to the previous viewmodels.
Winforms perfectly suitable for MVVM pattern. It supports data-binding (not so powerful as in WPF)
I know that I am slaughtering MVVM a bit, using it the way I am. It
was a work around, since my views contained user controls, which I had
to get to "talk to" the view model, which they did not know
By referencing view control in the viewmodel you break MVVM pattern. If you continue to "follow" MVVM - you are on your own, different kind of problems start gathering and after few weeks you decide that MVVM pattern not doable ;)
Simple suggestion for your particular case, without knowing much about application context, user control should now about viewmodels it affect on.
You can bind collection of viewmodels to the user control where it simple calls it's methods
private UserControl_OnActivate()
{
foreach (var viewmodel in ViewModels)
{
viewmodel.AddItem()
}
}
Now user control know about viewmodel and viewmodel know nothing about user control(view) - MVVM pattern.
Old viewmodel's references will be garbage collected when you update ViewModels collection with new ones.

MVVM Handling Window Management using Factory Approach

I delegate creation(showing) of my Windows to my WindowFactory, that attaches a ViewModel to the View and shows the window. It is injected into my MainViewModel Constructor parameters.
The factory itself is very simple:
public class ProductionWindowFactory : IWindowFactory
{
public void CreateNewWindow()
{
PhoneWindow window = new PhoneWindow();
{
window.DataContext = new phoneWindowViewModel();
}
window.Show();
}
}
Now, I'm aiming at implementing more functionality of my new windows, that will happen on certain button clicks IN that new window.
As I am fairly new to Factories in general, I'm struggling to grasp a certain concept:
Example:
We have a ViewA that has a ViewModelA attached to it.
That view has a button with a command attached, that tells our WindowFactory to show a new ViewB.
ViewB has a ViewModelB and a close button, that tells it to close ViewB.
Now, since we shouldn't reference our ViewB in our ViewModelB, we have to somehow let it know which view it should close.
I have come up with possible ideas / solutions, but I would really
appreciate you letting me know which one follows the MVVM and Factory
pattern "the most", and which one is usually used in such situations.
Make our ViewModelB take an instance of windowFactory that created ViewB as a parameter on initialization, and build a method in the Factory that closes ViewB and is executed through button click -> command.
Create an IWindowManager? that inherits from IWindowFactory and build a WindowManager class, that extends the capabilities of our WindowFactory, and push it in ViewModel constructors as described above.
Any other correct solution, that I am completely unaware of?
Please bear in mind, that the above is just an example. Ideally, I'd like to implement more of advanced functionality to my windows, and have an ability to create & manage multiple different ones using that one factory.
I have not attached much code, since I'm still at the stage of learning and deciding which solution should I go with.
EDIT - REGARDING POSSIBLE DUPLICATE:
My question differs from the proposed duplicate, as the other one is simply about managing of closing windows - My question is about doing that as well, but following a FactoryPattern.
I have specified very clear guidelines in what I am trying to achieve and in what ways, that are completely different from the question linked.
First of all, the answer is none. The job of a factory is to create new objects, think of it as an elaborate new operator. Also, the idea of following a pattern "the most" is problematic in and of itself. You employ patterns because they help you achieve certain goals, e.g. you employ mvvm to evade coded-ui tests as much as possible, because they are fragile, normally.
That being said, what to do with its view is completely up to the view's view model.
Example: if one view model needs to close its own window, do it with a command as illustrated in the comment. If a view has a close all-button, its view model will have a dependency on some kind of window registry that can enumerate all open windows for the close all-command to close.
When looking at your view model, try to come up with an idea of what services it needs from the rest of the application, and inject those dependencies as interfaces. When implementing the interfaces, most likely there will be classes that implement more than one, e.g. WindowManager might implement IWindowFactory and IWindowRegistry thus making it very easy to put all newly created windows into the list of open windows. The window will have a dependency on the IWindowRegistry, too, most likely, to unregister itself when it gets closed.
The duplicate was not far off. Here is a simple adaptation of the scenario in OP
interface IView {
void Close();
}
class ViewAdapter : IView {
readonly Window view;
public ViewAdapter(Window view){
this.view = view;
}
public void Close() {
view.Close();
}
}
public class ProductionWindowFactory : IWindowFactory {
public void CreateNewWindow() {
var view = new PhoneWindow();
var viewAdapter = new ViewAdapter(view)
var viewModel = new phoneWindowViewModel(viewAdapter);
//Bind
view.DataContext = viewModel;
view.Show();
}
}
If the view model wants to instruct that the view be closed it can ask the injected contract to do so.

Dynamic dependencies in deep object graphs - what am I doing wrong?

I'm trying to modify some existing code to use Castle Windsor as an IoC container.
The application in question is document-oriented. So it has an object graph that relies on data for specifying the data source that can't be known at registration time, and will change every time the object graph is resolved. However, this dependency is a few layers into the object graph, so I can't just pass it as an argument to container.Resolve() since Windsor doesn't propagate inline dependencies.
The solution I've come up with instead is to use the typed factory facility to generate a factory which can resolve every dependency in the graph, and have Document's constructor take an instance of this factory as well as a string specifying the data source. The factory is specified at registration time, and the data source is specified at resolution time. The constructor takes over from there, manually polling the factory to resolve is dependencies. The result looks something like this:
public interface IDataSource { /* . . . */ }
public interface IWidgetRepository { /* . . . */ }
public interface IWhatsitRepository { /* . . . */ }
// Implementation generated by Windsor's typed factory facility
public interface IFactory
{
IDataSource CreateDataSource(string path);
IWidgetRepository CreateWidgetRepository(IDataSource dataSource);
IWhatsitRepository CreateWhatsitRepository(IDataSource dataSource);
void Release(IDataSource dataSource);
void Release(IWidgetRepository widgetRepository);
void Release(IWhatsitRepository whatsitRepository);
}
public class Document
{
private readonly IDataSource _dataSource;
private readonly IWidgetRepository _widgetRepository;
private readonly IWhatsitRepository _whatsitRepository;
public Document (IFactory factory, string dataSourcePath)
{
_dataSource = factory.CreateDataSource(dataSourcePath);
_widgetRepository = factory.CreateWidgetRepository(_dataSource);
_whatsitRepository = factory.CreateWhatsitRepository(_dataSource);
}
}
This absolutely works, and does accomplish the goal of having Windsor take charge of dependency resolution. Or at least, I can easily reconfigure the application by modifying the registration code. At the moment I'm still making one call to container.Resolve() for every Document that gets created, but I believe that sin can easily be amended with a second Typed Factory.
However, it still feels wrong. Windsor is in charge of newing up objects and (somewhat) managing their lifetimes, sure. But it's not really injecting those dependencies into Document's constructor; instead the constructor is pulling them out of the factory. Worse, by passing the instance of IDataSource into the factory methods, it's taken charge of managing the object graph. That seems like a huge subversion of the inversion to me.
So, what am I missing?
EDIT
To clarify, what I think I'm supposed to be shooting for is for Document's constructor to look more like the below.
public Document (IDataSource dataSource, IWidgetRepository widgetRepository, IWhatsitRepository whatsitRepository)
{
_dataSource = dataSource;
_widgetRepository = widgetRepository;
_whatsitRepository = whatsitRepository;
}
That way Windsor is in direct control of supplying all the objects' dependencies using constructor injection. That's actually what the constructor signature looks like in the original code, but I was unable to get it to work with Windsor because container.Resolve() doesn't propagate inline dependency parameters. So I can't just do:
var document = container.Resolve<IDocument>(new { dataSourcePath = somePath }); // throws an exception
because Windsor doesn't pass dataSourcePath on to DataSource's constructor, much less make sure that a DataSource instantiated with that path is passed on to the other constructors.
An answer to another question points out that this is by design - doing otherwise would introduce coupling. This is a no-no, since one shouldn't mandate or assume that implementations of an interface have particular dependencies. Sadly, that points out another way I think the code I came up with is wrong, since Factory.CreateWidgetRepository() and Factory.CreateWhatsitRepository() imply just that sort of assumption.
I believe I've found the correct solution. Apparently the available documentation wasn't quite explicit (verbose?) enough to bang the concept through my thick skull the first twelve times I read it, so I'll make an attempt to document it in more detail here for the sake of others who might be as helpless as I am. (I'll also let it sit a while before accepting in the hope that someone else might come along with any other/better suggestions.)
Long story short, Typed Factory Facility is the wrong tool for the job.
--
The trick is to use the DynamicParameters facility in the fluent registration API, which is (rather sparsely) documented here and in the last section here.
What DynamicParameters lets you do is directly modify the collection of inline parameters that was supplied when the container was asked to resolve a component. This dictionary can then get passed on up the resolution pipeline, making it available to sub-dependencies.
DynamicParameters has three overloads, each taking a single delegate as its parameter. These delegate types aren't explicitly documented, so for the sake of posterity here's what ReSharper (I'm too lazy to download the source.) tells me their declarations look like:
public delegate void DynamicParametersDelegate(IKernel kernel, IDictionary parameters);
public delegate ComponentReleasingDelegate DynamicParametersResolveDelegate(IKernel kernel, IDictionary parameters);
public delegate ComponentReleasingDelegate DynamicParametersWithContextResolveDelegate(IKernel kernel, CreationContext creationContext, IDictionary parameters);
DynamicParametersDelegate is for the most basic case, where you just need to supply parameters that won't be managed by the container. That probably works for me, but in keeping with my tendency to find the complicated option first I ended up making a beeline for the second option, which is to supply a delegate which manually pulls dynamic parameters out of the container. Since Windsor's managing the component's lifetime in that case, you need to make sure it's being released. That's where DynamicParametersResolveDelegate comes in - it's just like the first one, except it also returns a ComponentReleasingDelegate (public delegate void ComponentReleasingDelegate(IKernel kernel);) which Windsor can use to release components at the appropriate time.
(The third, DynamicParametersWithContextResolveDelegate, is presumably for modifying the creation context. I don't know enough about how Windsor works to actually understand what the preceding sentence means, so I'll have to leave it at that.)
That allows me replace the constructor from my example with the much better-looking:
public class Document
{
private readonly IDataSource _dataSource;
private readonly IWidgetRepository _widgetRepository;
private readonly IWhatsitRepository _whatsitRepository;
public Document (IDataSource dataSource, IWidgetRepository widgetRepository, IWhatsitRepository whatsitRepository)
{
_dataSource = dataSource;
_widgetRepository = widgetRepository;
_whatsitRepository = whatsitRepository;
}
}
The factory is removed entirely. Instead, the magic goes in the component registration code for IDocument:
container.Register(Component.For<IDocument>()
.ImplementedBy<Document>()
.DynamicParameters(
(k, d) =>
{
// ask for an IDataSource, passing along any inline
// parameters that were supplied in the request for
// an IDocument
var ds = k.Resolve<IDataSource>(d);
// Add it to the dictionary. This makes it available
// for use when resolving other dependencies in the tree.
d.Add("DataSource", ds);
// Finally, pass back a delegate which can be used to release it
return (r) => r.ReleaseComponent(ds);
}));
So now I can ask for an IDocument with exactly the line of code I had been looking for:
var document = container.Resolve<IDocument>(new { dataSourcePath = somePath });
and the container starts by invoking that DynamicParameters delegate, which supplies the container with a DataSource for the supplied path. From there the container's able to figure the rest out for itself so that the same instance of DataSource gets passed to the constructors for all three of the other objects in the dependency graph.
I have the same issue. The problem I have with the above solution is that you will be calling :
var document = container.Resolve<IDocument>(new { dataSourcePath = somePath });
at each point where you need an IDocument. I think I should really be resolving all of my objects at a single point in the program and not using the container anywhere else. In other words, resolving a factory from the container once, and then using that factory at other points in the program. I think you were on the right track initially. Having said all that, I can't offer a better solution.

How to properly use a LINQ2SQL DataContext object; creating anew each use causes headaches

So, in learning LINQ2SQL (don't tell me it's a dead technology please, I'm not switching to EF for simple applications) I have read numerous times that the DataContext class is meant to be created and destroyed frequently. Great, a lightweight object that I can use to access my database. However, in practice this seems to cause nothing but trouble. For example, if I load up a DataGrid like so changes to entity objects don't seem to be tracked and calling DataContext.SubmitChanges has no effect:
void LoadUI()
{
using( var db = new TestDataContext() )
{
// use DataLoadOptions.LoadWith<T> if we need
// access to foreign key/ deferred objects.
masterGrid.ItemsSource = db.Customers.ToList();
detailsGrid.ItemsSource = // this is always set to a collection of Settings
// for the currently selected user in masterGrid.
// just a simple foreign key relationship
}
}
void UpdateName( string newName )
{
using( var db = new TestDataContext() )
{
var customer = ((Customer)masterGrid.SelectedItem);
customer.Name = newName;
db.SubmitChanges() // !!! database is not updated !!!
}
}
So what gives? Creating a new DataContext object when accessing the DB seems to be the accepted/preferred practice, yet it doesn't seem to work in the most trivial of cases. It appears that object tracking doesn't work in this scenario, so how could one possibly use the DataContext class like this in practice? Am I missing something here? (Note: I really do hope I am actually missing something simple.
I have to assume that is the case, but I don't know what the answer is yet. Currently I am just keeping a single DC around for the life of the app, which I know is probably not a good idea). Thanks in advance for any advice you can offer.
BTW, if any of you know of a comprehensive article/serie4s of articles which describe the ins-and-outs of the DataContext class I would love to read it. I haven't found any examples which go beyond trivial updates/inserts/deletes.
The answer is that you have 2 ways (and a lot more!) to solve this problem.
The Object Instance in your grid belongs to DataContext #1. In your UpdateName method you create a new DataContext #2. How can DataContext #2 know that an object from DataContext #1 has changed? Never. So: Use DataContext #2 to retrieve the Customer Object from the database and use the retrieved Object to change the property.
Another way is to use DTO´s. This way is far to long to describe, but the principle is that you create a class that has got all Properties a Customer has but nothing else (=> this class is not connected to your DataContext anymore) and after changing properties on it you reconnect the class to your DataContext and save it.
Hope i could help you.
void LoadUI()
{
using( var db = new TestDataContext() )
{
// use DataLoadOptions.LoadWith<T> if we need
// access to foreign key/ deferred objects.
masterGrid.ItemsSource = db.Customers.ToList();
detailsGrid.ItemsSource = // this is always set to a collection of Settings
// for the currently selected user in masterGrid.
// just a simple foreign key relationship
}
}
void UpdateName( string newName )
{
using( var db = new TestDataContext() )
{
var customer = ((Customer)masterGrid.SelectedItem);
var freshLoadedCustomer = db.Customers.FirstOrDefault(cust=>cust.Id == customer.Id);
if(freshLoadedCustomer != null)
{ freshLoadedCustomer.Name = newName; db.SubmitChanges();}
}
}
Changed objects can only be updated with the datacontext with which they were created. A datacontext is typically created once for every unit of work (e.g. a page or form that gets some objects, does some things with it and updates them in the db).
EDIT 2, In reaction to FooWombat's comment : For a more real-world example, read Datacontext Lifetime Management on Rick Strahl's blog. I goes in depth how to implement handling datacontext so that everything happens behind the scenes and you can select/update/delete your linq2sql objects without thinking (much) about it.
EDIT 1 : Also, if you google around a bit, you will also find a method called Attach. This method is meant to be used for objects that have been deserialized and then serialized back. It mentions to not try to attach objects from another datacontext. However, in this blogpost you have a example to (ab)use Attach so that you exactly can do this. I would only use it if you are in a pinch and really need to transfer objects from one datacontext to another. It's not really a recommended practice.
From the blogpost :
public partial class Employee
{
public void Detach()
{
this.PropertyChanged = null; this.PropertyChanging = null;
// Assuming there's a foreign key from Employee to Boss
this.Boss = default(EntityRef<Boss>);
// Similarly set child objects to default as well
this.Subordinates = default(EntitySet<Subordinate>);
}
}
You can use this Detach method to do this :
public static void UpdateEmployee(Employee employee)
{
using (HRDataContext dataContext = new HRDataContext())
{
//attach to datacontext
employee.Detach();
dataContext.Employees.Attach(employee);
//save changes
dataContext.SubmitChanges();
}
}
The magic words are "Data Binding." This is what you need to display data, and it's also what you need to save data back to the database.
The reason that your above code doesn't work is that it provides a read data binding path, but not a write data binding path. In other words, you've created a read-only list from the DataContext, but you haven't provided an actual way to write the changes back to the database.
The easiest solution might be to create a writable data path for your data grid, rather than trying to track and save the changes from the data grid manually. There's a number of ways to do this. One way that I know of is to use an ObservableCollection. The ObservableCollection provides notifications when items get added, removed, or when the entire list is refreshed. This allows you to hook code into those events to provide the saving function.
However, initially your best bet might be this search.

MVVM: How to design a window hosting different applications?

I am trying to implement a simple WPF data analysis application using the MVVM design pattern, in which one can use several different methods to analyse some data (loaded from files).
In the first screen, the user should be able to choose the method he likes to employ. After he has done that, and loaded the data, the area previously occupied by the method selection screen should be replaced by the analysis results.
Currently, my MainWindowViewModel has a property "CurrentViewModel" of type object, that can be set to either the method selection viewmodel or on of the analysis results viewmodels, which are then rendered by using datatemplates.
The problem I am facing is, that I don't know how the different viewmodels should communicate.
The method selection screen needs a
list of available methods.
The main screen needs to know what method was
selected and choose the approriate
viewmodel to display the results.
The data loaded somehow needs to get into the class doing the actual work, and the results viewmodel needs to know about this to know where to get its data from.
Everything I can think of leaves the MainWindowViewModel to do all the negotiating between the different viewmodel and model classes.
How would I optimally design this?
For what it's worth, I helped implement a module for a similar Composite Application. So what follows is based on anecdotal experience,
To your first point, our application or "shell" needs an explicit enumeration of "available" methods. We can supply this any way we wish, either explicitly (via config) or implicitly (via reflection). As a preference, I favor the former as it is less "magical".
To your second point, in addition to an explicit enumeration our shell must maintain a map from choice to implementation. Again, this may be accomplished any number of ways, but typically our enumeration is a list of "Types", and when a type is selected we request an implementation of that type from a factory. The easiest way to implement this pattern is to leverage an Inversion of Control container, such as Castle Windsor, Unity, Ninject, etc. To be honest, I don't remember what we used internally.
For example, consider,
// a simple Plain Old C Object that describes business methods.
public class BusinessMethod
{
// user-friendly name
public string Name { get; set; }
// type that actually implements
public Type ImplementationType { get; set; }
}
// ... meanwhile, back on the ranch ...
public void OnBusinessMethodSelection ()
{
// 1. if selected
if (BusinessMethodList.SelectedItem != null)
{
// 2. retrieve selected item
BusinessMethod selected =
(BusinessMethod)(BusinessMethodList.SelectedItem);
// 3. request implementation of selected item from
// IoC container
object implementation =
_container.Resolve (selected.ImplementationType);
}
}
To your third point, we need a way for disparate parts to communicate. Unfortunately we cannot rely on design-time methods (ie Command and Data bindings), so we must implement our own Event Aggregation service. Basically a "singleton" (as in single instance not static class) that knows about subscribers and publishers, and preferably an implementation that offers strong typing of arguments. Fortunately for us, many a greater man have gone before us, and we may benefit from their experience. Check out Kent Boogaart's Event Hub.
Here is an example of how we would use an Event Aggregator
// an example of a strongly typed subject. notice how subject
// defines content. semanticly, when someone creates and publishes
// an instance of this subject, they are requesting someone show
// an analysis view based on data content,
public class AnalysisSubject
{
// subject content, in this case a data result from
// a business method
public object Data { get; set; }
}
public class MainWindow : ISubscriber<AnalysisSubject> ...
{
// use whatever implementation of an IoC container we like
// here i assume we abstract from implementation and use a
// custom interface IContainer that exposes functionality
// that we need
private readonly IContainer _container = null;
public class MainWindow ()
{
// we're teh r00tz! we create an instance of IoC
// container for use throughout application
IContainer _container = new CustomContainer ();
// our container exposes both parameterized and
// type-parameterized resolve methods
IEventHub events = _container.Resolve<IEventHub> ();
events.Subscribe<AnalysisSubject> (this);
}
#region ISubscriber<AnalysisSubject>
// part of strongly typed subscriptions is that we
// may now handle strongly typed publications! yay!
public void Receive (AnalysisSubject subject)
{
// 1. request to display analysis of data
Type analysisType = subject.Data.GetType ();
// 2. get view control based on payload type
//
// NOTE: implicit usage below is not consistent
// with previous invocations, here we are submitting
// a type of something we already have, and actually
// want back something that knows how to handle it.
// most IoC containers can provide this functionality
// through "facilities" add ons that accept a
// parameter\discriminator like below, and produce
// something in return.
Control control = (Control)(_container.Resolve (analysisType));
// [alternatively] if the above is too "magical" where
// IAnalysisFactory is an interface we define for this
// express purpose
//IAnalysisFactory factory = _container.Resolve<IAnalysisFactory> ();
//Control control = factory.GetAnalysisControlFor (analysisType);
// 3. assign subject data to control
Control.DataContext = subject.Data;
// 4. display control
}
#endregion
}
And an example of publication
public class SomeBusinessView
{
private readonly IEventHub _events = null;
// we cannot function without an event aggregator of
// some kind, so we declare our dependency as a contructor
// dependency
public SomeBusinessView (IEventHub events)
{
_events = events;
}
public void DoMyThang ()
{
// 1. do some business
MyBusinessData data = SomeBusinessFunction ();
// 2. publish complete event
AnalysisSubject subject = new AnalysisSubject () { Data = data, };
_events.Publish (subject);
}
}
Every View typically gets a viewmodel. If you are dealing with nested usercontrols inside one window, using multiple viewmodels (one per control) may be overkill.
If you have a viewmodel per control and are disconnected regarding communication between them then you can either have a common model that is universal to all the viewmodels OR have a global event provider that allows models to talk to eachother. (Something they all can reference for change notifications etc).
If you don't use a viewmodel per control then have the viewmodel bound to the main window in which all nested controls report to the main window which reports to the viewmodel for the main window.
Could the data source of the selection be bound to the types of ViewModels you have and the path possibly be the name of each (be it a string property for a formatted name or the Type name explicitly). On Selection you then have the relevant object that has been selected.
Possibly each of the ViewModels references a common provider which as you say performs the results analysis and the two different Views simply display the same data in different ways.

Categories

Resources