Can a custom GUI button contain application logic? - winforms

this is a OO design question
I am making a memory game (card, 2 selections, if right continue on, otherwise turn moves to the other player).
I have a separation between the UI layer and the logic layer. events are implemented in the logic layer to report of interesting events to the UI layer.
I have a control called ButtonCard that inherits from Button and represents a card. it contains properties that represent it's location in the gameboard (x,y)
My question is about what is the correct object-oriented way to let the logic layer know that a click has been made:
override the onClick method (or register to the click event within the buttonCard), and there - let the logic layer know that it has been clicked (thereby requesting it to be revealed)
the Form that contains all the buttonCards is registering to all of their click events, will let the logic layer know about the click
The way I see it, There are benefits and disadvantages to both ways. the first method is proper OO in that, it makes more sense for the card object to pass the information along, and why should there be a middle-man? and the middle-man could even be considered a benefit, because the logic is contained in a central designated location.
What makes more sense to you guys?

...events are implemented in the logic layer to report of interesting events to the UI layer
I recommend used the Observer pattern
the simple and best way..
on the C# you can use Events
e.g:
public class LogicLayer
{
public event SomeEventHandler Notice = delegate{};
...
protected void notify(LogLevel level)
{
...
Notice();
}
}
...
public delegate void SomeEventHandler();
...
//Subscribers
LogicLayer.Notice += new SomeEventHandler(innerNotify);
...
// UI layer:
void innerNotify()
{
buttonCard.Text = ...
}
for real sample you can see, e.g.: my plugin for Visual Studio source on C#
Also see - MVVM

Related

MVVM: Provide a service to work with a specific part of the UI?

let's say that in my application, there is an user interface for representing a (geographic) map. It is integrated into the application as a UserControl and has its view model behind it.
Now, suppose I want to provide other parts of my application with a generic service interface to perform common tasks on the map (zoom, pan etc.) and not worry about the UI specifics. I could give away direct reference to the viewmodel, but I am pretty sure I would violate separation of concerns principle, not to mention it would be less testable.
So there are few questions:
Does it make sense and is it good practice to implement such services (which act as an intermediate link to the UI) in the first place?
Since the service operates directly on the map's viewmodel, should it be the viewmodel itself which implements the service interface?
Is it appropriate for the service interface to provide events (e.g. besides providing a method to change the map scale, provide an event that the map scale was changed as well)? Or is it preferable to employ some kind of event broadcaster (aggregator) mechanism to push such notifications out of service interfaces?
Thanks in advance for your help.
Consider using the Messenger in the MVVM Light toolkit. See more in another SO answer:
https://stackoverflow.com/a/2700324/117625
EventAggregator is the another mechanism which establish communication between disconnected view models. I believe all the other parts of your application will be using the same MVVm and will have viewmodel to do the operations. Publish event say Zoom with required arguments from other parts of the app and catch it in the map using the subscribe mechanism.
http://msdn.microsoft.com/en-us/magazine/dd943055.aspx#id0420209
Prism has a good implementation of Event Aggregator. you can use that part.
Whenever you need two view models to communicate (or something similar, such as a button that wants to invoke a command on a view model other than its own), the best practice I've found is use a messaging channel. (MVVM Light has the Messenger class; Prism and Caliburn.Micro both have an EventAggregator.) When the target of the command is instantiated (your map view model), it will register for specific commands on a messaging channel. When an invoker (such as a button) is instantiated, it can then send commands over that same channel. This keeps your components loosely coupled. Commands from the messaging channel can be easily mocked for unit testing. It also opens up other avenues to you, such as having multiple maps open at the same time (simply use a different messaging channel or some sort of token).
I'd skip the whole service interface in your case. When using an event aggregator, it doesn't really add much. Depending on the size and complexity of your code base, you might want to keep it around so it describes the commands available for a map, but that only makes sense if you have more than a handful of commands. In that case the service would register as the end point for commands on the messaging channel and would then have to forward those commands on to a map view model. (See? Doesn't add much and only seems to complicate things.)
Skip the events. They don't seem to add anything.
What if you had an aggregate Command object which specified the appropriate behaviour? I'm going to try to flesh your question out a little bit to specifics, correct me if I'm wrong:
Let's suppose that there are two relevant parts of your app - a map component, which can be zoomed and panned etc, and a set of controls, which present the user interface for zooming, panning and selecting between them - sort of a set of mode selectors. You don't want either of them to have a direct reference to the other, and the temptation is to have the map know directly about its set of controls, so that it can catch events from them and switch mode state appropriately.
One way to take care of this would be to have a set of CompositeCommands (available from the Prism Application Guidance) libraries inside an object injected into each of them. That way you get decoupling and a strong description of interface (you could also use events if you were that way inclined).
public class MapNavigationCommands{
public static CompositeCommand startPanning = new CompositeCommand();
public static CompositeCommand startZooming = new CompositeCommand();
public static CompositeCommand setViewbox = new CompositeCommand();
}
Your mode controls, up in the Ribbon, register with your DI framework to have that injected (not wanting to introduce DI into this example, I've just referenced these static members directly).
public class ModeControls : UserControl{
...
public void PanButtonSelected(object sender, RoutedEventArgs e){
MapNavigationCommands.StartPanning.Execute(this); //It doesn't really care who sent it, it's just good event practice to specify the event/command source.
}
}
Alternatively, in XAML:
...
<Button Command={x:Static yourXmlns:MapNavigationCommands.StartPanning}>Start</Button>
...
Now, over on the map side:
public class PannableMapViewModel{
public PannableMapViewModel(){
MapNavigationCommands.StartPanning.RegisterCommand(new DelegateCommand<object>(StartPanning));
MapNavigationCommands.SetViewbox.RegisterCommand(new DelegateCommand<Rectangle>(SetViewBox));
}
private void StartPanning(object sender){
this.SetMode(Mode.Pan); //Or as appropriate to your application. The View is bound to this mode state
}
private void SetViewbox(Rectangle newView){
//Apply appropriate transforms. The View is bound to your transform state.
}
}
Now you have a decoupled, strongly specified interface between two controls, maintaining ViewModel separation, which can be mocked out for your tests.

Navigating from one child page to another in Silverlight

We are using Silverlight MVVM pattern in our application. In the application there is a mainpage (which does not change) and there are child pages, these child pages changes depending on the operation performed by the user. Untill now I have been using code-behind for navigation between different child pages, the code goes like this :
ChildPage2 obj = new ChildPage2 ();
Dialog_Box.Children.Clear();
Dialog_Box.Visibility = Visibility.Visible;
Dialog_Box.Children.Add(obj );
But as I am using MVVM pattern I want to do the same using my ViewModel. Is there a way to do the same (Navigation) using ViewModels.
Please help, thanks in advance.
Vaibhav
Couple of basic rules:
ViewModels should not know about how they are displayed. They are purely glue between views and real data objects & business logic.
Views only know how to display data with a certain shape. They should not know where the data is coming from (the exception that breaks this rule is using DomainDataSources... but that's another story).
Look at the navigation features available in Silverlight (try creating a sample Business application in Visual Studio). Your views are then created when hyperlinks are clicked based on configured mappings.
The alternative (to do it in code) is to introduce controllers into MVVM. This maintains the separation of concerns between views, viewmodels and data, but adds a level of complexity I usually reserve for PRISM-based apps. Best you try the hyperlink/url mapping option.
The way I solved this before was to have properties in the ViewModel that each child page would bind to:
public class YourViewModel : INotifyPropertyChanged
{
public Visibility FooVisibility { get { /* ... */ } }
public Visibility BarVisibility { get { /* ... */ } }
}

I'm in MVVM ViewModel hell

So far, I am really happy with the way things have gone in my app's transition from typical click event handlers everywhere, to complete GUI decoupling. Now I'm running into something I can't quite figure out, and it's related to a window that I want my GUI to pop up, and it needs to display information from the model.
I guess the short version of my question is, is it absolutely forbidden in MVVM to allow the model to have a reference to a ViewModel? Here's my scenario: I have a bank of LEDs that cycles through RGB values very quickly. I would like a window in my GUI to display the updated colors via databinding with a ViewModel. I have the Window + UserControl working fine with a mockup ViewModel in a test application, but now I have to put this Window into my real application.
The particular mode I'm running in one that simulates what the hardware is doing. When I command the model to cycle through the colors, it starts a thread that changes the necessary class member variables' values.
My current implementation of MVVM is basically polling all of the time. To get other LEDs to update elsewhere, I have a thread running that calls a function in the ViewModel. This updates the properties, and so the GUI automatically updates since I'm using databinding. The problem in my LED example is that simulating the color sequence is done in a thread, so if I need to have a ViewModel poll for values, it will likely be slow due to excessive locking of the LED variables.
Therefore, I'm hoping that someone can recommend another approach to this problem. So far, the only thing I could really think of is to have the Window datacontext be an LEDViewModel, and then also pass the LEDViewModel to the Model. Then when I call the RGB cycling function, it can change the necessary ViewModel properties as necessary, and I won't need to use any locking at all.
Does this make sense? Any advice would be really appreciated.
Have you tried just implementing the INotifyPropertyChanged interface on your model?
It would seem to me that this should perform well enough. When the color state changes on your model, you can fire off the PropertyChanged event, update the view model state from that notification, and have the view update via a binding on the view model.
Why not use eventing on some sort of message broker for your application?
The easiest way to do this would be to use the Messenger in MVVMFoundation: http://mvvmfoundation.codeplex.com/
An example of this would be:
public class MyHardwareModel
{
private void OnHardwareLEDChanged() // or whatever
{
SharedMessages.Messenger.NotifyColleagues(SharedMessages.LEDCHANGED);
}
}
And then in your view model, when it spins up, you register for notification of these messages while that instance of the view model is alive:
public class MyHardwareViewModel
{
public MyHardwareViewModel()
{
SharedMessages.Messenger.Register(SharedMessages.LEDCHANGED, UpdateLeds);
}
private void UpdateLeds()
{
//Update ObservableCollection here.
}
}
The message mediator/broker pattern is really useful in these situations for so much more than just this. The Messenger built into MVVMFoundation is pretty powerful... in my sample I'm using pretty generic messages, but you can sent more typed messages with parameters.
There is a similar function built into Prism / Composite Application Guidance if you are using that called the EventAggregator. It's used in a similar way.
Hope this helps.
A simple approach would be to perform the polling regularly, say every 50ms. This can be done very easily using a timer, and will be less resource consuming than constant polling from a thread. 50ms seems a reasonable interval, even if your LEDs actually cycle faster, because the user won't have the time to see the color change anyway...

OOP vs case statement in Windows forms application

I have a software design question. Say I have a Windows form with some elements and I have a customer object. A customer can either be business, private or corporate for example.
Now, all the decisions of what is going to happen in the form will depend on the customer type. For instance, certain elements will be hidden, certain label text will be different, etc...events will respond differently.
Obviously, one way to code this will be to use CASE statement each time the decision needs to be made. Another way would be to have a Customer class and 3 other classed such as BusinessCustomer, PrivateCustomer and CorporateCustomer inherit from the base class. In the latter, a question then arises: how are you going to incorporate a windows from into it....
Edited
I had an idea: can I embed forms within forms? My reqs don't dictate two windows being shown at once, so I don't have to use MDI. But to simplify my design based on some ppl's comments here, I would like to maintain 3 different customer forms, and embed inside the main form on the fly. That way three GUIs are separated and I won't have to deal with every control's visibility.
I am assuming I can just add a form to another form, such as this:
Form child_form = new Form();
parent_form.Controls.Add(child_form);
Those decisions really shouldn't be made in the GUI. You should have a ViewModel behind your GUI that makes those decisions, and that you write unit tests for. (Or a Presenter, or a Controller -- different names that all mean roughly the same thing: get the decisions out of the GUI class and into something you can unit test.)
Then your ViewModel would have e.g. a Boolean property for each element that the GUI would disable, and a method for each action you could take (CloseCustomerAccount() or whatever).
As long as the Form is created for a particular type of customer, and the customer won't change to a different type of customer during the lifetime of the form, you could just pass your Customer object (that stores all of the actual customer data) to the ViewModel's constructor, and then pass your ViewModel to your Form's constructor. The form could set all its Enabled properties right after it calls InitializeComponent(). On the other hand, if the customer type could change, then your ViewModel needs to expose some events for the Form to hook, so the form knows when to re-run its Enabling logic.
Your question then moves out of the Form and into the ViewModel. Do you have one ViewModel class with a bunch of case statements, or three ViewModel classes (maybe with a fourth that's a base class) that use polymorphism, and a factory method somewhere that decides, based on the particular customer, which ViewModel class to instantiate?
I'd let your code be the guide there. Start with the simplest approach, which is probably case statements. Write a unit test for every behavior you care about. If the case statements start to get too awkward, then add a ViewModel descendant for each customer type, and start extracting the case statements into virtual methods. Your tests will catch you if you make a mistake during the refactor.
If you do have 3 different windows, each handling a specific type of customer than there won't be much point in working with the base class or a contract. You could be smart though with a factory class that takes a customer class and determines the correct screen to use.
I've run into this quite a bit. I end up with a base window that handles the generic stuff and then extend it for each concrete type.
I agree with Joshua Belden's answer. Three separate forms for different kinds of customers would likely be the easiest to maintain.
Also, in case you didn't know already, you can derive from a Form class and tweak it in a derived Form class. This is even supported by the designer.
However, I'd like to offer an alternative:
The Bridge Pattern: separate an abstraction from its implementation so the two can vary independently.
What you could do is this:
Create three separate UIImplementation classes. These classes could tweak the UI, and the events for the Customer form. In order to gain access to the private members of the form, you would need to declare the UIImplementation classes as nested within the CustomerForm class. (Use partial classes to separate these into different files). If the form itself is significant, and the tweaks are insignificant, this may be good option. It's difficult to say.
Just go for the three classes implementing some abstract Customer interface. In your app you would have a variable customer of type Customer and an object of a particular Customer type would be stored in there. Your GUI could then just rely on the interface and invoke methods on the customer variable regardless of what customer would be actually interacting with the GUI.
Have a look at this article.
I would go with an MVP type approach and define CustomerPresenter class that exposes a boolean property that will derive your UI controls' enable/disable state via binding.
public class CustomerPresenter
{
private Customer _customer;
public CustomerPresenter(Customer customer)
{
_customer = customer;
}
public bool EnableUI
{
get
{
//TODO: put your customer type basic logic here (switch statement or if/else)
return _customer.Type == CustomerType.Business;
}
}
}
public CustomerForm: WinForm
{
private CustomerPresenter _customerPresenter;
public CustomerForm(){};
public CustomerForm(Customer customer)
{
_customerPresenter = new CustomerPresenter(customer);
}
private void CustomerForm_Load(object sender, EventArgs e)
{
_someButton.DataBindings.Add("Enabled",_customerPresenter,"EnableUI");
}
}
The solution should be driven by data, not your code.
So if you tag various controls as being visible in state "A", "B", or "C", then a single method could look at its state and know which controls to make visible or not.
You know you did it right when adding new controls for state "D" takes no code changes aside from those required to add the controls themselves.
You might also look at breaking the form down into 4 sub-forms, shared, sub-form a, sub-b, then displaying both "Shared" and "Sub-a" together on a parent form ...

Open dialog in WPF MVVM

I have an application that need to open a dialog from a button where the user enters some information.
At the moment I do it like this (which works fine)
The button click generates a command in the ViewModel.
The ViewModel raises an event which the Controller listens to.
The Controller works out the details of the new window (i.e. View, ViewModel & model) and opens it (ShowDialog)
When the window is closed the Controller adds the result to the eventargs and returns to the ViewModel
The ViewModel passes the information to the Model.
There are a lot of steps but they all make sense and there is not much typing.
The code looks like this (the window asks for the user's name)
ViewModel:
AskUserNameCommand = DelegateCommand(AskUserNameExecute);
...
public event EventHandler<AskUserEventArgs> AskUserName;
void AskUserNameExecute(object arg) {
var e = new AskUserNameEventArgs();
AskUserName(this, e);
mModel.SetUserName(e.UserName);
}
Controller:
mViewModel.AskUserName += (sender,e) => {
var view = container.Resolve<IAskUserNameView>();
var model = container.Resolve<IAskUserNameModel>();
var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model);
if (dlg.ShowDialog() ?? false)
e.UserName = model.UserName;
}
My question is how the horizontal communication works in the MVVM pattern.
Somehow it seems wrong to let the controller be involved in the data transfer between the models.
I have looked at the mediator pattern to let the models communicate directly. Don't like that idea since it makes the model depending on implemetations details of the GUI. (i.e. if the dialog is replaced with a textbox, the model need to change)
I don't like most of the current suggestions for one reason or another, so I thought I would link to a nearly identical question with answers I do like:
Open File Dialog MVVM
Specifically the answer by Cameron MacFarland is exactly what I do. A service provided via an interface to provide IO and/or user interaction is the way to go here, for the following reasons:
It is testable
It abstracts away the implementation of any dialogs so that your strategy for handling these types of things can be changed without affecting constituent code
Does not rely on any communication patterns. A lot of suggestions you see out there rely on a mediator, like the Event Aggregator. These solutions rely on implementing two-way communication with partners on the other side of the mediator, which is both hard to implement and a very loose contract.
ViewModels remain autonomous. I, like you, don't feel right given communication between the controller and the ViewModel. The ViewModel should remain autonomous if for no other reason that this eases testability.
Hope this helps.
i use this approach for dialogs with mvvm.
all i have do do now is call the following from my viewmodel to work with a dialog.
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
I have come across similar problems. Here is how I have solved them, and why I have done what I have done.
My solution:
My MainWindowViewModel has a property of type ModalViewModelBase called Modal.
If my code needs a certain view to be modal, it puts a reference to it in this property. The MainWindowView watches this property through the INotifyPropertyChanged mechanism. If Modal is set to some VM, the MainWindowView class will take the VM and put it in a ModalView window where the appropriate UserControl will be shown through the magic of DataTemplates, the window is shown using ShowDialog. ModalViewModelBase has a property for DialogResult and a property called IsFinished. When IsFinished is set to true by the modal VM, the view closes.
I also have some special tricks for doing interactive things like this from backgroundworker threads that want to ask the user for input.
My reasoning:
The principle of modal views is that other views are disabled, while the modal is shown. This is a part of the logic of the View that is essentially lookless. That's why I have a property for it in the MainWindowViewModel. It I were to take it further, I should make every other property or command for all other VM's in the Main VM throw exceptions, while in modal mode, but I feel this to be excessive.
The View mechanism of actually denying the user any other actions, does not have to be performed with a popup window and showdialog, it could be that you put the modal view in the existing window, but disable all others, or some other thing. This view-related logic belongs in the view itself. (That a typical designer can't code for this logic, seems a secondary concern. We all need help some times.)
So that's how I have done it. I offer it only as a suggestion, there is probably other ways of thinking about it, and I hope you get more replies too.
I've used EventAggregator from Prism v2 in similar scenarios. Good thing about prims is that, you don't have to use entire framework in your MVVM application. You can extract EventAggregator functionality and use it along with your current setup.
You might have a look at this MVVM article. It describes how a controller can communicate with the ViewModel:
http://waf.codeplex.com/wikipage?title=Model-View-ViewModel%20Pattern&ProjectName=waf

Resources