A little while ago, I wrote this SO post looking for a good way to handle UI and business layer interaction, and I liked the answer which was to use the MVVM pattern.
So I did so quite successfully, but I'm a bit stuck with a problem using this pattern. Indeed, in some part of my UI, one of my buttons is supposed to open a dialog with the details of an item displayed in a ListView.
I saw this SO post asking about the same question, but I didn't quite understand the answer and I wonder if it is suitable in my case. The idea was to use the Unity framework and to call the window associated with the view in the repository using App.Container.Resolve<MyChildView>().ShowDialog(), for example.
However, my problem is that I have implemented the ViewModels in project separate from the UI client project. I did this in order to be able to use the VMs from another client if need at a later stage of the project. First question, was that a wrong implementation of the pattern?
Second question, as my ViewModels project isn't actually in the client's project, and hence I do not have access to the App global variable. Therefore, I don't think I can use the solution I found in the previously mentioned post. Is there any workaround?
1) Your implementation is not wrong at all. I regularly separate UI, VM, and models into separate assemblies.
2) As you mentioned, it isn't appropriate to reference App within a VM. Consider App a "UI class" and treat it as such. Have you considered injecting the appropriate UnityContainer into your VM?
If injecting the container isn't an option for you, think about adding a controller to your solution or using the Mediator pattern as suggested by other answers in that SO post you mentioned.
Try this. Set up a new thread, initialize and show your window (You can also use ShowDialog() instead of Show()), and then convert the thread to a UI thread by calling Dispatcher.Run() which will block until the window is closed. Then, afterwards, you can handle the dialog result however you want.
new Thread(() =>
{
MyDialogWindow m = new MyDialogWindow();
m.ShowDialog();
Dispatcher.Run();
// Handle dialog result here.
}).Start();
Be sure to add an event in your dialog for when you close the window, to have the Dispatcher stop. Add this to your constructor of the dialog:
Closed += (_,__) => Dispatcher.InvokeShutdown();
Related
Is it possible to keep a view models in a .NET Standard project?
I would like to have a common view models for two different applications: one written in WPF and the second one in Blazor.
The problem appeared when I wanted to invoke my ICommand's event CanExecuteChanged?.Invoke(this, EventArgs.Empty); in a separate thread and got an error: "System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.". I don't see Dispatcher support in .NET Standard, or any alternative to it. Can such view models be shared between different platforms (eg. Windows, Mac and Linux) at all?
Nice idea. Assuming SPA, the way I would try to implement this would be to register a class with the dependency injection that would stand in for the ICommand.
The example code is from a class that has ballooned from a small suggestion I found on the web to a lot of functionality.
I have just snipped out a few pieces of code, if you want to try it this way and you need more info, let me know I will give a complete in code answer.
The #onclick method on the button could then call a method that raises the event in the injected class.
The subscribing class could be on the same Component or anywhere else.
Also if your WPF isn't one of those where the developer is showing off how well they understand WPF you should be able to write a script that would go a long ways towards automating this conversion.
On a side note I definitely see the Resemblance of Blazor Serverside with WPF. To me it is as if WPF got a long due update and it is improved in nearly every area. I too approach it as if it was WPF, but I don't try to do a straight conversion because it is so improved.
public void ShowNotification(NotificationMessage notificationMessage)
{
Message = notificationMessage;
NotifyMessageArrived();
}
private void NotifyMessageArrived()
{
OnRaiseMessageArrivedNotification?.Invoke();
}
public event Action OnRaiseMessageArrivedNotification;
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.
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.
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 :)
First of i am not a UI developer and this is probably a very simple problem.
What i have is a external service that I subscribe to an event, when ever that event fires a service picks this up, manipulates the data in some way then gives the UI the data to display
What i am unsure of is how to archetect this and keep the dependancy between the service which will tell the UI to update and the UI as loose as possible.
Can anyone suggest a stratagy for this or post me some links on examples or an open source project to actually look at some working code.
I am using c# and ether wpf or winforms for this.
Cheers
Colin G
How simple is this application?
The simplest solution is to have the data access/manipulation in one object, and have the UI passed as an interface into that object. With the UI interface methods, you can give data to the UI but let the UI handle displaying the data in a GUI thread-safe manner.
If it's a more complex application, I'd say it would make more sense to look into something like MVC or MVP. Or MVVM for WPF, maybe look at Bea Costa's blog for databinding examples.
My solution to this problem is to create a timer in your ui, and have your ui subscribe to the 'onTick' method. Then, at every timer tick, have the UI look at the service and figure out what data to display.
There's a lot of ways to skin this cat, but without knowing a little more about your requirements and your existing infrastructure, let me suggest you use an EventBroker / Mediator for this. This is an easy way to implement a kind of Publisher / Subscriber type of relationship without worrying about too much of the plumbing.
If you are using Prism, I'd suggest using the EventAggregator.
If not, you might consider using the "Messenger" implementation of an EventBroker available with the MVVMFoundation stuff that John Smith wrote. It's not really dependent on you using MVVM or WPF and does what you are looking for:
http://mvvmfoundation.codeplex.com/
Hope this helps.
then gives the UI the data to display...
I would suggest you to have a service agent layer which will raise an event and pass a DTO. This event should be subscribed by the layer which contains objects bound to the UI. Once this layer receives the DTO, update the UI.