Updating MainWindow Property from separate MVVM Module - c#

I am looking to implement a "JQuery" style spinner in a WPF application. As this spinner will be triggered from some separate PRISM modules and I want the spinner to cover the whole application window I need to get access to a property in the MainWindow.
I have a property in the MainWindow but I am not able to see it from the other modules.
I have tried Application.Current.MainWindow but no luck.
I have also tried using the Application.Current.Properties[] but I do not know how to trigger a OnPropertyChanged event.
Can someone point me in the right direction please.
Update:
Here are some screenshots and a better description of what I want to do.
Ok, here is an example of my issue. I have an application that contains the following:
WPFApp
WPFApp.Module1
WPFApp.Module2
WPFApp.Module3
WPFApp.Module4
The WPFApp MainWindow contains 2 regions, a Menu region (on the left hand side) and a Content region.
Each module contains 2 views:
A menu view, which is loaded into the MainWindow Menu region
A content view, which is loaded into the MainWindow Content region
In each of the Module content views I want to perform a task that will take a few seconds and while the task is being performed I want to show a “Ajax Style” spinner that will cover the whole application window.
To have used the spinner class detailed here: WPF Spinner via MVVM & Attached Properties
I have been able to use this by adding the AsyncNotifier.Trigger (detailed in the link above) to each of the modules content view, see below.
My problem is:
If I want the spinner to cover the whole application window then I need to add the AsyncNotifier.Trigger to the MainWindow. I also need to expose a property from the MainWindow responsible for showing the spinner and be able to access this from each of the modules.
Any ideas on how to do this?
Update:
Ok, I think I might be getting a bit further but still a little bit stuck on how everything fits together.
I have created my Interface and put it into my Infrastructure module so every other module can access it.
I am using the following piece of code to load my modules from my AggregateModuleCatalog class.
/// <summary>
/// this.Catalogs is a readonly collection of IModuleCatalog
/// Initializes the catalog, which may load and validate the modules.
/// </summary>
public void Initialize()
{
foreach (var catalog in this.Catalogs)
{
catalog.Initialize();
}
}
My problem is that I am unsure of where I should put the SpinnerViewModel? Should it be in my Main project.
Also, where should I pass in the singleton using Constructor injection?

I would look at implementing the mediator pattern here. This is already present in Prism in the form of the EventAggregator
Basically, it sounds like you want to publish control messages of a certain type to any subscribers - in this case you have:
Subscribers
MainWindow
Publishers
Module 1
Module 2
Module 3
The modules should publish a message to signal that they want to 'busy' the MainWindow whilst work is being done/module is being loaded etc
The key thing is that they should not be aware of the MainWindow in any way. This keeps the solution decoupled, MVVM friendly, reusable and easily maintained. This method uses dependency injection, which is usually a good idea :)
In order for this to work, the modules need to take a dependency on the EventAggregator service (there is an IEventAggregator interface in PRISM which is your service interface) and should then publish messages to it
First you need an event which will serve as the message class. Obviously this needs to be visible from both the publisher and subscriber, so may need to sit in an external reference. This needs to inherit from CompositeWpfEvent and you should provide a generic argument for the message payload.
public class BusyUserInterfaceEvent : CompositeWpfEvent<bool>
{
}
(I suppose you could just directly use CompositeWpfEvent<bool> for this which may work equally as well but is not specific enough if you decide to include more event types which use bool as payloads)
Then you need to publish events of the above type from your module
public class Module1
{
private IEventAggregator _eventAggregator;
public Module1(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public DoSomeWork()
{
// Busy the UI by publishing the above event
_eventAggregator.GetEvent<BusyUserInterfaceEvent>().Publish(true);
}
public FinishDoingSomeWork()
{
// Unbusy the UI by publishing the above event with 'false'
_eventAggregator.GetEvent<BusyUserInterfaceEvent>().Publish(false);
}
}
The MainWindow should also take a dependency on the EventAggregator service and should subscribe to any messages of a certain type. If work is to be done on the UI thread (as it is in this case) you should subscribe using ThreadOption.UIThread
public class MainWindow
{
private IEventAggregator _eventAggregator;
public MainWindow(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
// Subscribe to any messages of the defined type on the UI thread
// The BusyUserInterface method will handle the event
_eventAggregator.GetEvent<BusyUserInterfaceEvent>().Subscribe(BusyUserInterface, ThreadOption.UIThread);
}
public BusyUserInterface(bool busy)
{
// Toggle the UI - pseudocode here!
TickerActive = busy;
}
}
Whilst I have used this pattern in a couple of frameworks successfully before, I admit that I haven't used PRISM so the above code might not be quite right, however, the docs seem concise:
http://msdn.microsoft.com/en-us/library/ff921122.aspx
Using this pattern decouples any components, so it's easy to stop the MainWindow from subscribing to the events and to move the subscriber to a parent component if needs be without touching the implementation of the publishers.
This means you could swap the MainWindow for a completely different window and load your modules in during some part of your application lifecycle, and as long as it was subscribing to these event types it would still busy/unbusy based on the message publishing from the modules. It's a very flexible solution.
PRISMs implementation also provides subscription filtering so you can selectively listen for events.
Additionally, since you are aggregating events there's a lot you can do with this to allow inter-module communication. The only challenge you have is making sure everyone is aware of the message types, which is why an external dependency may be needed to hold the message types

Am I missing something? Should this be as easy as this?
App.xaml.cs
public partial class App
{
public static Window MainWindow {get;set;}
}
MainWindow.xaml.cs
public MainWindow()
{
App.MainWindow = this;
InitializeComponent();
}
public void Spinner(bool show)
{
// Your code here
}
Now in MVVM, the idea would be the same, just don't do it in code behind. You could create a singleton (Singleton has a static instance) for the spinner to bind to and then any module can mess with the singleton property.
If you like Dependency Injection, create an interface, create an object that implements that interface, have the Spinner bind to that object. Then inject that object as the interface into the modules when they are loaded.
Here is a singleton ViewModel that implements an interface. Your Prism projects need to know only about the interface. But your code that loads your Prism modules should know about both the interface and the singleton. Then when the Prism Modules are loaded, the singleton would be passed in (feel free to use whichever injection method is easiest: constructor injection, method injection, or property injection).
using System.ComponentModel;
namespace ExampleCode
{
/// <summary>
/// Interface for managing a spinner
/// </summary>
public interface IManageASpinner
{
bool IsVisible {get;set;}
// Add any other properties or methods you might need.
}
/// <summary>
/// A singleton spinner ViewModel for the main window spiner
/// </summary>
public class SpinnerViewModel : INotifyPropertyChanged, IManageASpinner
{ #region Singleton and Constructor
/// <summary>
/// Singleton instance
/// </summary>
public static SpinnerViewModel Instance
{
get { return _Instance ?? (_Instance = new SpinnerViewModel()); }
} private static SpinnerViewModel _Instance;
/// <summary>
/// Private constructor to prevent multiple instances
/// </summary>
private SpinnerViewModel()
{
}
#endregion
#region Properties
/// <summary>
/// Is the spinner visible or not?
/// Xaml Binding: {Binding Source={x:Static svm:SpinnerViewModel.Instance}, Path=IsVisible}
/// </summary>
public bool IsVisible
{
get { return _IsVisible; }
set
{
_IsVisible = value;
OnPropertyChanged("IsVisible");
}
} private bool _IsVisible;
// Add any other properties you might want to include
// such as IsSpinning, etc..
#endregion
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
}
Hope you can connect the dots from here.
Added Feb 12
Maybe use Method injection? I am not sure you can though.Can you edit the IModuleCatalog interface or the Catalog class? If not, skip this and go to the next idea.
foreach (var catalog in this.Catalogs)
{
catalog.Initialize(SpinnerViewModel.Instance);
}
Maybe your Catalogs should implement a second interface and use property injection instead of constructor injection.
public interface IHaveASpinner
{
public IManageASpinner Spinner {get;set;}
}
Now, have all your catalogs that implement IModuleCatalog also implement IHaveASpinner.
Then have your code do this:
foreach (var catalog in this.Catalogs)
{
catalog.Initialize();
var needSpinner = catalog as IHaveASpinner;
if (needSpinner != null)
{
needSpinner.Spinner = SpinnerViewModel.Instance;
}
}
Where I should put the SpinnerViewModel?
I would suggest your main project. It depends on your design. Do all the modules already reference your main project? If so, then put it in your main project. If not, then perhaps there is a project the main project and all the modules already reference? You could even create a separate project/dll specific for your spinner, but only if you have to as that might be overboard unless you have a strict design with rules for what can reference what.

You shouldn't need a VM just for the spinner. What I do is have the spinner itself (animation, icon, whatever) in my main window's view, and have the main window VM implement the following interface:
public interface IApplicationBusyIndicator
{
bool IsBusy { get; set; }
}
Using your favourite IoC container (I use Castle), I just inject IApplicationBusyIndicator into other VMs. Whenever one of these starts some long-running task it just sets IsBusy to true (then back to false when it's finished). The busy indicator in the main window view has its Visibility property bound to the main window VMs IsBusy property (using a boolean-to-visibility converter of course).
If, in your scenario, there is some architectural constraint preventing VMs in other modules from being injected with an instance of the main window VM, then you could use Prism's event aggregator to publish a message to say "application busy", and have the main window VM subscribe to the event, and show the busy indicator.

If you are looking to create more of some "visual" style / interface of a spinner, I suggest looking into creating your own subclass spinner (if you need special functionality behind it), and then create your own customized style for its look / behavior. Then when you put the spinner on the forms, just use a spinner of the class/style you designate and they should function for you well.
Here is one of my own learning about styles, but simple label
Another link where I helped someone walking through creating their own custom class/style which MIGHT be what you are trying to globally implement.
And a link to template / style defaults to learn from

Related

MVP in windows forms

I want to implement MVPO pattern in my windows forms application. As you know there is 1:1 means there is one presenter for one view.
So basicly we can have:
public class MainPresenter
{
IMainView _mainView;
public MainPresenter(IMainView mainView)
{
_myView = myView;
}
}
My question is can one presenter use other presenter so for instance:
public class MainPresenter
{
IMainView _mainView;
ISomeOtherPresenter _otherPresenter;
public MainPresenter(IMainView mainView, IOtherPresenter otherPresenter)
{
_mainView = myView;
_otherPresenter = otherPresenter;
}
}
As a reference i went through video tutorial by Robert Marquez. At his 10 video serie at 10th one he used one rpesenter inside other one
Reference link
at 35:39 you will see his MainPresenter has dependency to IHelpAboutPresenter.
To me it's logical because if HelpAboutView (form) can be opened by button from MainView it's logical MainPresenter has to have access to HelpAboutPresenter which was presented on the video. If not that way how to do so because all the people saying 1:1 and here we have 1 presenter uses other presenter.
It is a bit of a code small to has a cross dependency like that. If you need functionality from another presenter, it is likely the presenters have something in common. So perhaps they should derive from the same base class. Then they can easily share logic without complicating your dependency graph.
public class BasePresenter
{
protected void SharedMethod()
{
//Code that you need to call from both presenters
}
}
public class MainPresenter : BasePresenter
{
IMyView _myView;
public MainPresenter(IMyView myView)
{
_myView = myView;
}
private Foo()
{
SharedFunction();
}
}
public class OtherPresenter : BasePresenter
{
public OtherPresenter(IMyView myView) : base()
{
_myView = myView;
}
private Bar()
{
SharedMethod();
}
}
I would assert that there isn't anything inherently wrong with the approach although one could probably go about it another way.
The "main" view could be acting more along the lines of a front controller. The pattern is more often associated with web-applications although it may still be applicable to desktop applications. For instance, the main MDI view may be the front controller.
Typically a front controller would have some dispatching mechanism to have individual requests (such as menu clicks in a desktop application, or url-based resources in a web-based application) handled by a specific request handler. There is therefore a slight indirection that decouples the front controller from the specific implementation.
In the case of the linked video the relationship is just a bit more coupled in that the About box request (if I understand correctly) is being handled not by a specific request handler but by the front controller.
What makes this appear odd is the fact that the front controller is implemented using the MVP pattern.

Winforms - MVP Pattern: Using static ApplicationController to coordinate application?

Background
I'm building a two-tiered C# .net application:
Tier 1: Winforms client application using the MVP (Model-View-Presenter) design pattern.
Tier 2: WebAPI RESTful service sitting on top of Entity Framework and SQL Server.
Currently, I have questions relating to the overall architecture of the Winforms client application. I'm new to programming (about a year) but I've made good progress with this application. I want to step back and re-evaluate my current approach to check that I'm generally heading in the right direction.
Application Domain
The Winforms application is a fairly simple security personnel tracking application. The main view (Form) is the focus of the application, and has different sections which group content into functional areas (e.g. a section for tracking personnel schedules, a section for tracking who is assigned where, etc.). A menu on the side of the application launches secondary views (e.g. history, statistics, contacts, etc.). The idea is that the app could be used by a security office to organize daily operations and then keep a detailed history of everything in a database for reporting on in the future.
Technical Details
As mentioned, the Winforms client is built using the MVP pattern (passive view), focusing on using dependency injection as much as possible (via SimpleInjector IoC container). Each view (form) is paired up with a single presenter. The views implement interfaces, allowing the presenter to control the view (regardless of the concrete implementation). The view raises events for the presenter to subscribe to. Currently, presenters are not allowed to directly communicate to another presenter.
An application controller is used to coordinate the application. This is the area of my application architecture where I'm the most shakey (hence the post title). The application controller is currently used to:
Open new views (forms) and manage open forms.
Facilitate communication between application components via an event aggregator. One presenter publishes an event and any number of presenter can subscribe to that event.
Host session information (i.e. security context/logon, config data, etc.)
The IoC container is registered into the application controller at application start-up. This allows the application controller, for example, to create a presenter from the container, and then have all subsequent dependencies (view, services, etc.) to be automatically handled by the container.
Question
In order to make the Application Controller accessible to all presenters, I have created the controller as a static class.
public static class ApplicationController
{
private static Session _session;
private static INavigationWorkflow _workflow;
private static EventAggregator _aggregator;
#region Registrations
public static void RegisterSession(Session session) {}
public static void RegisterWorkflow(INavigationWorkflow workflow) {}
public static void RegisterAggregator(EventAggregator aggregator) {}
#endregion
#region Properties
public static Session Session
{
get { return _session; }
}
#endregion
#region Navigation
public static void NavigateToView(Constants.View view) {}
#endregion
#region Events
public static Subscription<TMessageType> Subscribe<TMessageType>(Action<TMessageType> action) {}
public static void Publish<TMessageType>(TMessageType message) {}
public static void Unsubscribe<TMessageType>(Subscription<TMessageType> subscription) {}
#endregion
}
Is this considered an acceptable practice to make a static class like this? I mean, it certainly works. It just feels... off? Are there any other holes that you can see in my architecture based on what I have described?
-
** EDIT **
This edit is made in response to Ric .Net’s answer posted below.
I have read through all of your suggestions. As I am committed to utilizing dependency injection to the fullest extent I can, I’m onboard with all of your suggestions. That was my plan from the beginning, but when I ran into things I didn’t understand how to accomplish via injection, I turned to the global static controller class to solve my problems (A god class it is becoming, indeed. Yikes!). Some of those questions still exist:
Event Aggregator
The defining line here is what should be considered optional, I think. I’ll provide a bit more context about my app before outlining my problem. Using web terminology, my main form generally acts like a layout view, hosting navigation controls and a notification section in the left menu, and partial views being hosted in the center. Coming back to winforms terminology, the partial views are just custom made UserControls that I treat like views, and each of them are paired up with their own presenter. I have 6 of these partial views hosted on my main form, and they serve as the meat and potatoes of the application.
As an example, one partial view lists available security guards and another lists potential patrol areas. In a typical use case, a user would drag an available security guard from the available list to one of the potential patrol areas, effectively becoming assigned to that area. The patrol area view would then update to show the assigned security guard and the guard would be removed from the available list view. Utilizing drag-and-drop events, I can handle this interaction.
My questions come when I need to handle other types of interactivity between the various partial views. For example, double clicking on guard that is assigned to a location (as seen in one partial view) could highlight that guard’s name on another partial view showing all personnel schedules, or bring up employee details/history on another partial view. I could see the graph/matrix of what partial views are interested in events occurring in other partial views as becoming quite complex, and I’m not sure how to handle that via injection. With 6 partial views, I wouldn’t want to inject the other 5 partial views/presenters into each one. I was planning on accomplishing this via the event aggregator. Another example I could think of is needing to update data on a separate view (its own form) based off an event that occurs on one of the partial views on the main form.
Session & Form Opener
I really like your thoughts here. I’m going to take these ideas and run with them, and see where I end up!
Security
What are your thoughts on controlling user access to certain functionality based on what type of account they have? The recommendations I’ve been reading online say that security could be implemented by modifying the views based on their account type. The thought being, if a user can’t interact with a UI element to kick off a certain task, then the presenter will never be asked to perform that task. I’m curious if you inject the WindowsUserContext into each presenter and do additional checks, especially for http service bound requests?
I haven’t done too much development on the service side of things yet, but for http service bound requests, I imagine you need to send security information along with each request so that the service can authenticate the request. My plan was to inject the WindowsUserContext directly into the winforms service agents that end up making the service requests (i.e. the security validation would not be coming from the presenter). In that case, the service agents could potentially do a last minute security check before sending off a request.
A static class is of course handy in some cases but there are a lot of downsides to this approach.
The tend to grow into something like a God class. You already see this happening. So this class violates SRP
A static class cannot have dependencies and therefore it needs to use the Service Locator anti pattern to get it's dependencies. This is not a problem perse if you consider this class to be part of the composition root, but nevertheless, this often heads the wrong way.
In the supplied code I see three responsibilities of this class.
EventAggregator
What you call Session information
A service to open other views
Some feedback on this three parts:
EventAggregator
Although this is a widely used pattern and sometimes it can be very powerful I myself am not fond of this pattern. I see this pattern as something that provides optional runtime data where in most cases this runtime data is not optional at all. In other words, only use this pattern for truly optional data. For everything that is not really optional, use hard dependencies, using constructor injection.
The ones that need the information in that case depend upon IEventListener<TMessage>. The one that publish the event, depend upon IEventPublisher<TMessage>.
public interface IEventListener<TMessage>
{
event Action<TMessage> MessageReceived;
}
public interface IEventPublisher<TMessage>
{
void Publish(TMessage message);
}
public class EventPublisher<TMessage> : IEventPublisher<TMessage>
{
private readonly EventOrchestrator<TMessage> orchestrator;
public EventPublisher(EventOrchestrator<TMessage> orchestrator)
{
this.orchestrator = orchestrator;
}
public void Publish(TMessage message) => this.orchestrator.Publish(message);
}
public class EventListener<TMessage> : IEventListener<TMessage>
{
private readonly EventOrchestrator<TMessage> orchestrator;
public EventListener(EventOrchestrator<TMessage> orchestrator)
{
this.orchestrator = orchestrator;
}
public event Action<TMessage> MessageReceived
{
add { orchestrator.MessageReceived += value; }
remove { orchestrator.MessageReceived -= value; }
}
}
public class EventOrchestrator<TMessage>
{
public void Publish(TMessage message) => this.MessageReceived(message);
public event Action<TMessage> MessageReceived = (e) => { };
}
To be able to guarantee events are stored in one single location, we extract that storage (the event) into its own class, the EventOrchestrator.
The registration is as follows:
container.RegisterSingleton(typeof(IEventListener<>), typeof(EventListener<>));
container.RegisterSingleton(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleton(typeof(EventOrchestrator<>), typeof(EventOrchestrator<>));
Usage is trivial:
public class SomeView
{
private readonly IEventPublisher<GuardChanged> eventPublisher;
public SomeView(IEventPublisher<GuardChanged> eventPublisher)
{
this.eventPublisher = eventPublisher;
}
public void GuardSelectionClick(Guard guard)
{
this.eventPublisher.Publish(new GuardChanged(guard));
}
// other code..
}
public class SomeOtherView
{
public SomeOtherView(IEventListener<GuardChanged> eventListener)
{
eventListener.MessageReceived += this.GuardChanged;
}
private void GuardChanged(GuardChanged changedGuard)
{
this.CurrentGuard = changedGuard.SelectedGuard;
}
// other code..
}
If another view will receive a lot of events you could always wrap all IEventListeners of that View in a specific EventHandlerForViewX class which get all important IEventListener<> injected.
Session
In the question you define several ambient context variables as Session information. Exposing this kind of information through a static class promotes tight coupling to this static class and thus makes it more difficult to unit test parts of your application. IMO all information provided by Session is static (in the sense that it doesn't change throughout the lifetime of the application) data that could just as easily be injected into those parts that actually need this data. So Session should completely be removed from the static class. Some examples how to solve this in a SOLID manner:
Configuration values
The composition root is in charge of reading all information from the configuration source (e.g. your app.config file). This information can there be stored in a POCO class crafted for its usage.
public interface IMailSettings
{
string MailAddress { get; }
string DefaultMailSubject { get; }
}
public interface IFtpInformation
{
int FtpPort { get; }
}
public interface IFlowerServiceInformation
{
string FlowerShopAddress { get; }
}
public class ConfigValues :
IMailSettings, IFtpInformation, IFlowerServiceInformation
{
public string MailAddress { get; set; }
public string DefaultMailSubject { get; set; }
public int FtpPort { get; set; }
public string FlowerShopAddress { get; set; }
}
// Register as
public static void RegisterConfig(this Container container)
{
var config = new ConfigValues
{
MailAddress = ConfigurationManager.AppSettings["MailAddress"],
DefaultMailSubject = ConfigurationManager.AppSettings["DefaultMailSubject"],
FtpPort = Convert.ToInt32(ConfigurationManager.AppSettings["FtpPort"]),
FlowerShopAddress = ConfigurationManager.AppSettings["FlowerShopAddress"],
};
var registration = Lifestyle.Singleton.CreateRegistration<ConfigValues>(() =>
config, container);
container.AddRegistration(typeof(IMailSettings),registration);
container.AddRegistration(typeof(IFtpInformation),registration);
container.AddRegistration(typeof(IFlowerServiceInformation),registration);
}
And where you need some specific information, e.g. information to send an email you can just put IMailSettings in the constructor of the type needing the information.
This will also give you the possibility to test a component using different config values, which would be harder to do if all config information had to come from the static ApplicationController.
For security information, e.g. the logged on User the same pattern can be used. Define an IUserContext abstraction, create a WindowsUserContext implementation and fill this with the logged on user in the composition root. Because the component now depends on IUserContext instead of getting the user at runtime from the static class, the same component could also be used in an MVC application, where you would replace the WindowsUserContext with an HttpUserContext implementation.
Opening other forms
This is actually the hard part. I normally also use some big static class with all kinds of methods to open other forms. I don't expose the IFormOpener from this answer to my other forms, because they only need to know, what to do, not which form does that task for them. So my static class exposes this kinds of methods:
public SomeReturnValue OpenCustomerForEdit(Customer customer)
{
var form = MyStaticClass.FormOpener.GetForm<EditCustomerForm>();
form.SetCustomer(customer);
var result = MyStaticClass.FormOpener.ShowModalForm(form);
return (SomeReturnValue) result;
}
However....
I'm not at all happy with this approach, because over time this class grows and grows. With WPF I use another mechanism, which I think could also be used with WinForms. This approach is based on a message based architecture described in this and this awesome blogposts. Although at first the information looks as it is not at all related, it is the message based concept that let these patterns rock!
All my WPF windows implement an open generic interface, e.g. IEditView. And if some view needs to edit a customer, it just get's this IEditView injected. A decorator is used to actually show the view in pretty much the same way as the forementioned FormOpener does it. In this case I make use of a specific Simple Injector feature, called decorate factory decorator, which you can use to create forms whenever it is needed, just as the FormOpener used the container directly to create forms whenever it needs to.
So I did not really test this, so there could be some pitfalls with WinForms, but this code seems to work on a first and single run..
public class EditViewShowerDecorator<TEntity> : IEditView<TEntity>
{
private readonly Func<IEditView<TEntity>> viewCreator;
public EditViewShowerDecorator(Func<IEditView<TEntity>> viewCreator)
{
this.viewCreator = viewCreator;
}
public void EditEntity(TEntity entity)
{
// get view from container
var view = this.viewCreator.Invoke();
// initview with information
view.EditEntity(entity);
using (var form = (Form)view)
{
// show the view
form.ShowDialog();
}
}
}
The forms and decorator should be registered as:
container.Register(typeof(IEditView<>), new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(IEditView<>), typeof(EditViewShowerDecorator<>),
Lifestyle.Singleton);
Security
The IUserContext must the base for all security.
For the userinterface I normally hide all controls/buttons that a certain userrole doesn't have access to. The best place is to perform this in the Load event.
Because I use the command/handler pattern as described here for my all actions external of my forms/views I use a decorator to check if a user has permission to perform this certain command (or query).
I would advise you to read this post a few times until you really get the hang of it. Once you get familiar with this pattern you won't do anything else!
If you have any questions about these patterns and how to apply a (permission)decorator, add a comment!

MVVM Solution structure

I'd like to understand the best practice for structuring an MVVM solution.
Currently I've created a separate project for my View and my ViewModel. My View project references my ViewModel project. So far so good. When it comes to implementing navigation my ViewModel classes need access to the RootFrame in order to navigate around, but the RootFrame resides in App.xaml which is in the View project. So I have a circular dependency issue here.
Is there a recommended structure I should be using? I could just lump this all into one big project but in order to decouple the View and ViewModel I feel like having separate projects is a better approach.
When it comes to implementing navigation my ViewModel classes need access to the RootFrame
This is a false assumption.
You could use a message broker (a single object) that is responsible for distributing messages between publishers (ViewModels) and subscribers (some object that is responsible for opening Views).
Most MVVM frameworks have such a broker.
About the dependencies
The single responsibility of the Broker is to raise events. So, in general, it exposes a couple of methods that can be called by publishers and a couple of events that can be registered to by subscribers.
In MVVM you could use this mechanism to have a ViewModel raise the event that signals that a View should be opened and a View Manager that subscribes to this event. The View Manager should be able to instantiate a View and attach the correct ViewModel.
To prevent the ViewManager from needing references to all Views and ViewModels you could pass to the event logical names (just a string) and have the View Manager look up the matching View(Model) type by using reflection or a static list in a configuration file.
This way you do NOT need any circular references references. In fact, when you find you need references that go against the proper dependencies in MVVM, you should first doubt the setup and after that consider using a base class for the View and/or ViewModels.
There is no best practice for MVVM since it is a design pattern that everybody implements differently according to their preference. I've seen quite a few different implementations but have never seen a views and view models in separate projects. I would recommend just keeping them in different folders in the same project and put them in different namespaces.
e.g. Your View Models can go in a ViewModels folder and be in the namespace MyProject.ViewModels
Your Views can go in a Views folder and be in the namespace MyProject.Views
And the same for Models if you are using them
Check out Rachel's good answer in this post. I also like to separate my Views and ViewModels, because then I know when I screwed up MVVM ground rules.
Your ViewModel should not have any references to the View, but the View must have a reference to the ViewModel. Consider, for example, my custom SplashScreen factory (the two important lines are "var viewModel..." and "var splashScreen..."):
namespace MyCompany.Factories
{
using System.Threading;
using MyCompany.Views;
using MyCompany.ViewModels;
public static class SplashScreenFactory
{
public static SplashScreenViewModel CreateSplashScreen(
string header, string title, string initialLoadingMessage, int minimumMessageDuration)
{
var viewModel = new SplashScreenViewModel(initialLoadingMessage, minimumMessageDuration)
{
Header = header,
Title = title
};
Thread thread = new Thread(() =>
{
var splashScreen = new SplashScreenView(viewModel);
splashScreen.Topmost = true;
splashScreen.Show();
splashScreen.Closed += (x, y) => splashScreen.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
return viewModel;
}
}
}
The Factories project has references to both MyCompany.ViewModels and MyCompany.Views. The Views project only has a reference to MyCompany.ViewModels.
We first initiate the ViewModel from our caller (in this case, from SplashScreenFactory; or maybe from App.xaml.cs if you want; I prefer using my own Bootstrapper class for reasons beyond this discussion).
Then we initiate the View by passing the ViewModel reference into the View's constructor. This is called Dependency Injection. You may also need to write a Behaviour for the Window class in order to Close the window from your ViewModel. So now I can do the following from my Bootstrapper class:
/// <summary>
/// Called from this project's App.xaml.cs file, or from the Deals Main Menu
/// </summary>
public class Bootstrapper
{
private SplashScreenViewModel _splashScreenVM;
public Bootstrapper()
{
// Display SplashScreen
_splashScreenVM = SplashScreenFactory.CreateSplashScreen(
"MyCompany Deals", "Planning Grid", "Creating Repositories...", 200);
// Overwrite GlobalInfo parameters and prepare an AuditLog to catch and log errors
ApplicationFactory.AuditedDisplay(
Assembly.GetExecutingAssembly().GetName(),
() =>
{
// Show overwritten version numbers from GlobalInfo on SplashScreen
_splashScreenVM.VersionString = string.Format("v{0}.{1}.{2}",
GlobalInfo.Version_Major, GlobalInfo.Version_Minor, GlobalInfo.Version_Build);
// Initiate ViewModel with new repositories
var viewModel = new PlanningGridViewModel(new MyCompany.Repositories.PlanningGridHeadersRepository(),
new MyCompany.Repositories.PlanningGridLinesRepository(),
_splashScreenVM);
// Initiate View with ViewModel as the DataContext
var view = new PlanningGridView(viewModel);
// Subscribe to View's Activated event
view.Activated += new EventHandler(Window_Activated);
// Display View
view.ShowDialog();
});
}
/// <summary>
/// Closes SplashScreen when the Window's Activated event is raised.
/// </summary>
/// <param name="sender">The Window that has activated.</param>
/// <param name="e">Arguments for the Activated event.</param>
private void Window_Activated(object sender, EventArgs e)
{
_splashScreenVM.ClosingView = true;
}
Note that I have control over the SplashScreen's View by subscribing to the View's Activated event, and then closing the view with the "ClosingView" boolean INotifyProperty that sets the View's "Close" DependencyProperty in turn (sounds complicated, but once you get to know DependencyProperties, it becomes simple).
The point is, don't try to drive your navigation from RootFrame. Just view.Show() the RootFrame, and control the rest from RootFrameViewModel.
Hope this helps :-)

Caliburn ShowDialog and MessageBox

I'm making a small demo application for MVVM with caliburn.
Now I want to show a MessageBox, but the MVVM way.
For dialogs I created an event, that is handled in the ShellView (the root view)
and just calls WindowManager.ShowDialog with a Dialogs ViewModel type.
Seems to stick to MVVM for me.
But what is the way to show a messagebox and get its result (Okay or cancel)?
I already saw this question, but it contains no answer either.
Mr Eisenberg hisself answers with
"Caliburn has services built-in for calling custom message boxes."
Can anyone tell what he means with that? I don't see it in the samples.
As you mentioned, you just prepare the view model (e.g. ConfirmationBoxViewModel) and an appropriate view. You'll have to create two actions (after inheriting the view model from Screen, which is necessary to use TryClose. You can always implement IScreen instead, but that would be more work):
public void OK()
{
TryClose(true);
}
public void Cancel()
{
TryClose(false);
}
and then in your other view model:
var box = new ConfirmationBoxViewModel()
var result = WindowManager.ShowDialog(box);
if(result == true)
{
// OK was clicked
}
Notice that after the dialog closes, you can access the view model properties if you need to pull additional data from the dialog (e.g. Selected item, display name etc).
In the article A Billy Hollis Hybrid Shell (written by the framework coordinator) the author showed a nice way to handle both dialog and message boxes, but he used dependency injection (you can go without DI of course but it makes things simpler). The main idea is that you can let your main window, the one used as the application shell implement an interface that looks something like this:
public interface IDialogManager
{
void ShowDialog(IScreen dialogModel);
void ShowMessageBox(string message, string title = null, MessageBoxOptions options = MessageBoxOptions.Ok, Action<IMessageBox> callback = null);
}
and then he registers this interface with the IoC container, I guess you can use your imagination from there on and if you don't have time then you can look at the source code that accompanies the article.
When the root/main/shell view-model implements a kind of DialogService interface, every other view-model needing to show dialogs will end up with a dependency on the root view-model. Sometimes this might not be desiderable, e.g. if it could cause a dependency loop:
DialogService (aka RootViewModel) -> SomeViewModel -> RootViewModel.
A more involved approach to break this dependency chain (and actually invert it) is the following:
Implement a behavior that detects Window.OnSourceInitialized event and attach it to main view Window component. That is the event fired when the window handle is available. Upon event, behavior will notify some handler passed in via attached property:
<my:WindowSourceBehavior InitListener="{Binding WindowListener}" />
public class WindowSourceBehavior : Behavior<Window>
{
// ...
// boilerplate code for IWindowListener InitListener dependency property
// ...
attachedWindow.SourceInitialized += (sender, evt) =>
{
// ...
InitListener.SourceInitialized(sender as Window);
}
}
DialogService exposes a handler - or interface - as requested by behavior:
public class DialogService : IWindowListener
{
// ...
public void SourceInitialized(Window rootWindow) { /* ... */ }
}
In root view-model, (indirectly) get the DialogService injected as a dependency. During construction, sets view-model bound property, WindowListener, to the DialogService handler/interface:
public MainViewModel(IWindowListener dialogServiceInDisguise)
{
WindowListener = dialogServiceInDisguise;
}
public IWindowListener WindowListener { get; private set; }
Doing so, the DialogService is able to get a hold of root Window, and whichever view-model needs to show a dialog does not create a(n indirect) dependency on main view-model.

XAML C# Function across multiple windows

I've got a program I am working on that has multiple windows. The windows are similar in functionality and I want to have a single event handler to cover a button press event for each window in the application. Is this possible?
If you need to bind a handler in code behind you can encapsulate a handler by delegate and inject into the Windows which are required it.
For instance using Action<T>:
Action<string> commonHandler = (parameter) =>
{
// handler code here
};
class MyWindiow
{
public MyWindiow(Action<string> handler)
{
// store to local and assign to button click
// button.CLick += (o, e) => { handler(parameterToBepassed); }
}
}
I'd look into using a framework to help you out here. My favorite is Prism v4.
If you follow the M-V-VM design pattern you're life will be a lot easier. You'll need to understand Data Binding and DataContext.
That being said, if you decide to go this path, you can bind each of your windows to a command:
<Button Command="{Binding DoFooCommand}" Content="DoFoo"/>
You're ViewModel would have a DelegateCommand member to execute.
public class SomeViewModel : NotificationObject
{
public SomeViewModel()
{
DoFooCommand = new DelegateCommand(ExecuteFoo);
}
public DelegateCommand DoFooCommand { get; set; }
private void ExecuteFoo()
{
//Use the EventAggregator to publish a common event
}
}
And finally, somewhere else in your solution you'll have a code file/class that subscribes to the event and waits for someone to publish the event to process it.
public class SomeOtherPlace
{
public SomeOtherPlace()
{
//Use the EventAggregator to subscribe to the common event
}
public void FooBarMethodToCallWhenEventIsPublished(SomePayload payload)
{
//Do whatever you need to do here...
}
}
I realize some of the things were left out (such as what a "SomePayload" is... look into the EventAggregator information), but I did not want to get into it too much. Just give you a guide on where to go for information and some base code to work off of. If you decide to use the EventAggregator then you'll need to ensure that your subscribing call and publishing calls are utilizing the SAME instance of the EventAggregator. You can do this by looking into MEF. Prism is setup to work with MEF perfectly... I'm not going to lie. Doing all this requires a bit of a learning curve, but it will be worthwhile in the end when you can unit test your ViewModels easily and have your code loosely coupled. The EventAggregator is a great way for different classes to communicate to each other without relying on knowing about each other. And MEF is great for having a Container for your services that you want to utilize across your application.
Hope that gave you a bit of insight on how to go about doing what you want to do on the correct path.

Categories

Resources