When developping rather large applications using Prism and MEF/Unity I always reach a point where I should choose between using events, a service or maybe both. And I cannot decide what's most usable. Maybe something is wrong with my architecture (as in this decision shouldn't have to be made in the first place) but I don't see what.
Here's a typical example: my application has a main window and a lot of slave windows that are created on demand by modules or user actions. The application decides what a slave window's chrome looks and behaves like, remembers window placement etc while the content itself is created somewhere in the modules. There are also a lot of user actions resulting in hiding/showing/bringing to front of windows. To achieve all this, I currently have a WindowManager service that listens to CreateWindow/SetWindowState/.. events.
This has benefits:
classes using this only know about IEventAggregator (which they already use most of the time anyway for other events) and the events consumed by WindowManager, not WindowManager itself
classes like ViewModels don't deal with windows directly. Instead they refer to them by their title or id and small event classes that encapsulate just what's needed.
no need for a seperate IWindowManager interface just for the purpose of mocking it in a test
And withdrawals:
WindowManager could be used perfectly standalone, but now it needs to subscribe for events. Or probably better, some other class has to take care of that.
extending it to show a modal dialog is somewhat tricky: if a VM fires an event to show a dialog, it's of utter importance that the Publish call only returns after the dialog was closed
WindowManager is available as a service and it's in the CompositionContainer, why not use it as such anyway?
Using the service directly just shifts benefits/withdrawals around and there doesn't seem to be a clear winner.
Question: what would you use as guidance rules to pick one or the other, or would you rather always pick just one, or both? Is there something particularly wrong in my application design that I have to make this decision?
Events and services are used for different things. You don't have to choose between them, you can use them for different purposes. You would typically use event to notify listeners that something has happened. Example: users changes the font size in the application settings. You would send event to all listeners (e.g. viewmodels) so that the views update. Usually event is kind of thing for which you don't get a response (although you could attach e.g. callback function/action that the event listener would call).
What if your viewmodel needs to open new window? Usually the viewmodel shouldn't care how this new window is opened or whether it is modal or not. In this case it would be easy to use a service:
windowManager.ShowDetailsView();
The WindowManager (which you use through IWindowManager interface) is responsible for displaying the details view. Maybe it is a modal view or maybe there is some kind of slide animation. The point is that the viewmodel that uses IWindowManager doesn't care.
In some cases you might need to receive notification if users clicks Ok or Cancel. You can still use the IWindowManager by having method like this:
public void ShowEditView(Action userSavedChanged, Action userCancelled);
Then just call it from the viewmodel
windowManager.ShowEditView(this.SaveChanges, this.CancelChanges);
// in your viewmodel you have the SaveChanges and CancelChanges methods
private void SaveChanges()
{
// save the changes.
}
Hopefully this all makes some sense. After all it is friday :)
Related
Generally, I think it's good practice to use ICommands to handle button clicks that need to do something (such as save user input). However, when the button does something strictly on the UI, like open a modal dialog, the view model doesn't need to handle that, or even be aware it happened. In such cases, it seems like it makes more sense to just use the button's Click event handler, but mixing and matching like that seems like a potential anti-pattern. Am I correct in thinking so?
For example:
var openModalButton = new Button();
openModalButton.Click += OnModalButtonClick;
//Elsewhere in the view...
var saveInputButton = new Button { Command = _vm.SaveInput };
It's not inherently clear by looking at the code why one uses a command, and why one uses a click event.
Jedediah,
I usually do as you and mix and match. Usually (for me) there is only 1 or 2 cases like this, and the idea of patterns and architecture is to make the code easier to read and simplify things. Adding a lot of code just to ensure the MVVM pattern is followed seems like it complicates things in this case. That said, the way I've seen this usually handled is bind the button to your ViewModel with ICommand, and then use a "mediator" or "service" to launch the dialog. You could do a Google Search on: "HOw to handle opening a modal dialog the mvvm way " and/or see:
Open dialog in WPF MVVM
The "pretty" way to make a modal dialog in WPF with Prism and MVVM Pattern
Handling Dialogs in WPF with MVVM
Good luck!
Dave
Of course consistency is important as Robin pointed out. However there are scenarios when you'd not want the ViewModel to be involved. Then there's no choice and I think it is much better to break consistency here but not to break the pattern (MVVM) by handling stuff in the ViewModel that is not its job.
You took modal dialogs as an example and I do not agree that the ViewModel should not know about it. Of course the ViewModel is not allowed to directly open that dialog, settings its owner and the likes. But the dialog most probably is part of the workflow and it's just fine to know about the current state of the workflow in the ViewModel. So there should be a layer in between. A service or something similar that allows you to say "I want to show the UI for X" and that solves this by using a modal dialog. The ViewModel doesn't know about the modal dialog but it knows the current state, for example that it is asking the user whether to save changes. Of course this requires some kind of infrastructure handling the special cases and tricky parts. MVVM frameworks offer solutions for this.
If that sounds like overkill for your application simply put that event handling in the code behind of the view. It is not beautiful style but it does not break the MVVM pattern.
In one phrase: Better to mix than to violate the pattern.
I think it is an anti pattern, or not very cool thing at least,first because you're mixing the two approaches and that's not consistent, secondly because I believe that that needs always to be handled in a Command instead of an Event handler, why ?
the view model doesn't need to handle that, or even be aware it
happened. In such cases, it seems like it makes more sense to just use
the button's Click event handler
Not really, additionally to the fact that Commands help you separate your object from the logic that executes the Command thus it makes it loosely coupled, but it also help enhancing the reusability of your code, for instance someone in the future may want to change that button into a whole new control that might have a different event, and different args for the corresponding event ...
and that breaks your code, using a command however is better and is always compatible and reusable.
Moreover, Laurent Bunion explains in this article how Events are problematic :
For all their utility, event handlers have one problematic side
effect: they can create a tight coupling between the instance that
exposes the event and the instance that subscribes to it. The system
needs to keep track of event handlers so that they can be executed
when the event is raised, but the strong link this creates might
prevent garbage collection. Of course, this isn’t an issue if the
event handler is a static method, but it is not always possible to
handle all events with static methods only. This is a frequent cause
for memory leaks in .NET.
Another consequence of the tight coupling between an event and its
handler is that the event handler for a UI element declared in XAML
must be found in the attached code-behind file. If it is not there (or
if there is no attached code-behind file), the compilation will fail
with an error. This is especially an issue when working with list
controls and associated DataTemplates. When an element of the template
must be actuated, an event handler can be defined, but as a
consequence, the DataTemplate cannot be moved into an external
ResourceDictionary.
I'm writing a small text-editor like utility for our in-house staff to use to modify a bunch of company specific files. I want design this in such a way we minimize leaky handlers and would like to ask for opinions.
There are different actions done based on the type of file loaded. I have each in a separate class, I instantiate and pass through the active tab's instance of the richtextbox. The implementation then subscribes to the following:
SelectionChanged
TextChanged
Then depending on the type of file, they'll deal with their specific things. I've noticed that some of our internal devs don't unsubscribe from events and things leak. The control hangs around (It's not a MDI app, a panel + tab control + many richtextboxes).
What's a good way of delegating the resposibility of susbcribing to events to these implementations?
Should I write a proxy (which they all subscribe to) and my Richtextbox basically gets that proxy to call it for me when something happens - and I subscribe/unsubscribe as necessary when the tab changes? Are there any established patterns - maybe a Gang of Four? that may be what I should use?
Yes. just create proxy class based on type call respective class methods
Right now I am coding an application and am thinking that there has to be a better solution to what I am doing right now.
I have a main window which shall handle the settings of the program. Then I have further classes and windows. For example a language handler class and a form that is handling the user input needed for the "main function".
However, until now I always have to pass my main window to each of this classes, because the language handler shall be able to change the main window's strings. And the other form should also be able to pass data to the main Window.
If we imagine there will be much more classes and every class needs a copy of the main window this would consume a lot of resources depending on the main window's "size".
So, is there a better/more efficient way to communicate between these classes.
Common way to do that is to use observer pattern, which in .NET is events system. Simply said, your classes subscribe to each other's events and perform action when event is raised. As noted in comment, passing references is not memory heavy, but it results in tight coupling between different pieces of your code - observer pattern addresses that problem.
Another option is to consider you classes as services. Code them to an interface and then use dependency injection (aka Inversion of Control) to build up the object graph (You tell the IoC container you want a frmSomething and it will determine what services/classes it needs and instantiate them as appropriate).
This means that:
you only ever have to code against an interface not an implementation
your code is loosely coupled (You can swap an OldTranslator for a NewTranslator and as long as they both comply to the same interface, nothing has to be changed except the configuration of the container)
you can develop high-level features which rely on services that haven't been written yet and your code will compile
You can very easily change how your app works, at run-time if needs be, by changing what classes/services are registered in your container.
Have a look at Unity for the MS-Supported DI container. Castle Windsor is a popular alternative but there are many more
It's worth noting that passing a "Copy" of the main window around as you've said is not a bad thing - You're actrually only passing a reference (effectively a pointer) to the main window (since anything more complex than the real primitives are reference types). This means that there's very little overhead whatsoever
I would suggest you to use Galasoft or Prism MVVM implementations. There you can use their messaging service which is quite easy to use. The class that needs info just sends a message to the subscriber and they in turn can send all data needed. I think that this is the easiest way to handle communication.
in addition to the ans given by IVAN.. if we look at a higher level view without all those terminologies then you should probably create a static class which would server as InMemoryStorage and defines fields on it to save information
this what you will have complete control over what is being shared and multiple components can change it
moreover you can defined getters and setters and raise an event whenever the property is changed so that different forms or windows (views) can subscribe to the change and take action accordingly
So I've just started developing C# WinForm applications and each project I've been working on seems to be larger and requires more user functionality. If I add all of the functionality to one form, obviously it can get out of control very quickly. My last project I would divide up the functionality into individual Forms, and whenever someone say wanted to perform "Feature1" I would instantiate Feature1 Form and show it as a dialog with the main Form as it's owner (so they couldn't click off it).
I'm just curious of what other methods are out there for keeping code organized within Forms. If you are forced to have tons of features/functionality on a single form is there a good way to keep items organized? I simply hate having a code file with hundreds/thousands of lines long.
The answer may simply be in the design, try to design the UI up front so you can utilize multiple forms?
Another example I faced. I created a Tab Control and had about 5 tabs. Those 5 tabs had tons of features and were all stored in the same CS file. What other options did I have? Create a new custom TabControl class with my specific functionality for that tab in it?
I don't mind reading, so if there are decent articles out there feel free to link them!
The go-to method is a Controller/Presenter. The idea is that the window should only be responsible for actually handling the UI events of its controls, and it should do so by calling methods on a Controller which do the real work for the window. The window can either have the handlers necessary or it may link the UI events directly to Controller methods; the former is usually the easier method, but it can be tempting to sneak in a line of code here or there that really should be in the Controller method. By doing this, you sever the layout and presentation logic in the Form class with the business logic in the Controller.
Mark Hall's suggestion of User Controls is also a good one. By creating UserControl classes for tabs or for common UI control combinations, you sever the logic responsible for laying out that part of the UI from the main form's code, and the control then just "drops in" and the window works with it in a much simpler way. This is a must for implementing custom but reusable controls; the fundamental tenet of DRY is that if you have two lines of code in two different places doing the same job to two different but interchangeable things, those lines of code should be merged into one place.
I have used UserControls in my projects to group functionality into separate objects that can then be added to your Form.
I tend to split my logic code from the UI as recommended. If you do this, you need to be somewhat cautious with how calls are made across the application to avoid Cross Thread Exceptions. I was taught to create delegates and events to update the UI from the logic class, but MSDN of course also has a lot of information on making thread safe calls.
I know this is a late answer, but if anyone still reads this question, another way to reduce the number of lines of code in your form is to use Data Bindings. If you are using properties, Data Bindings make it so that you don't have to constantly write handlers just to do something like PropertyName = textBox.Text;. Data Bindings work with both datasets and objects.
I'm starting to train Prism (CAL) with a small application and faced some problems.
I'm creating multiple instances of my MainView, which itself contains some regions, and display them in the Shell.
I'm using locally scoped regions to easily handle view injections within my MainView.
Currently I'm searching for a way of communication between the views (viewModels) inside the MainView. Composite events could do it, but when I publish those events, they are handled in all instances of my MainView, which I really don't want.
Is there a way of raising "locally scoped" composite events like with locally scoped regions? Or may be there's a better way of communicating between views in my case?
It's also possible to create locally scoped EventAggregator and register in a child UnityContainer, created in the MainView (at the same place, where locally scoped region is created).
This is an equivalent to a locally scoped regions imho.
Pass form sender as an argument. (Anyway, there must be a way to distinguish your application's windows - use it.) When you recieve the event, check whether current form ReferenceEquals to sender (Or, check the form 'key').
After much discussion, EventAggregator was selected. Sharing with other in case they are in the same situation and our thought process might help them:
(Problem statement: Refer to my previous comment)
The main View (ViewModel) which has regions to hold views from other modules and which also forms the TabItem view is responsible for cleaning up itself and child views it contains. Hence on TabItem closing event this main View (ViewModel) should inform its child views to gracefully shutdown.
Both EventAggregator and .Net Eventing were thoroughly explored from various aspects as potential candidate for sending the shutdown message.
Since, in a Prism decoupled environment the main View should be technically unaware of its child Views and vice versa, EventAggregator was chosen.
One issue with event aggregator is that it publishes events to whole application, but our requirement was to filter events coming from the tabitemview being closed. The EventAggregator was designed to use a filter to verify if the shutdown request is coming from the same tabitemview (we used scoped regionmanager for every tabItem and this scoped regionmanager was used as the filter) only then it executes the shutdown action. This ensures that triggering shutdown in one tab does not close child views in other tabs which happen to have the same regionname.
Thanks,
RDV