I'm a beginner with Eclipse RCP and I'm trying to build an application for myself to give it a go. I'm confused about how one actually goes about handling model objects. None of the examples I can find deal with the problem I'm having, so I suspect I'm going about it the wrong way.
Say I need to initialise the application with a class that holds authenticated user info. I used my WorkbenchWindowAdvisor (wrong place?) to perform some initialisation (e.g. authentication) to decide what view to show. Once that's done, a view is shown. Now, that view also needs access to the user info I had earlier retrieved/produced.
The question is, how is that view supposed to get that data? The view is wired up in the plugin.xml. I don't see any way I can give the data to the view. So I assume the view has to retrieve it somehow. But what's the proper place for it to retrieve it from? I thought of putting static variables in the IApplication implementation, but that felt wrong. Any advice or pointers much appreciated. Thanks.
The problem you are facing here is in my opinion not RCP related. Its more an architectural problem. Your view is wired with business logicand!
The solution can be done by two (common) design-patterns:
Model-View-Controler (MVC)
Model-View-Presenter (MVP)
You can find plenty information about this in the web. I am going to point a possible solution for your particular problem using MVP.
You will need to create several projects. One is of course an RCP plugin, lets call it rcp.view. Now you create another one, which doesnt make UI contributions (only org.eclipse.core.runtime to start with) and call it rcp.presenter. To simplify things, this plugin will also be the model for now.
Next steps:
Add the rcp.presenter to the
dependencies of rcp.view (its
important that the presenter has no
reference to the view)
Export all packages that you are
going to create in the rcp.presenter
so they are visible
In rcp.presenter create an interface
IPerspective that has some methods
like (showLogiDialog(), showAdministratorViews(User user), showStandardViews(User user))
Create a class PerspectivePresenter that takes IPerspective in the constructor and saves it in an attribute
In rcp.view go to your Perspective, implement your interface IPerspective, and in the constructor create a new reference presenter = new PerspectivePresenter(this)
call presenter.load() and implenent
this in the presenter maybe like this
code:
public void load()
{
User user = view.showLoginDialog(); // returns a user with the provided name/pw
user.login(); // login to system/database
if(user.isAdministrator())
view.showAdministratorViews(user);
else
view.showStandardViews(user);
}
As you can see, the view just creates a reference to the presenter, which is responsible for all the business logic, and the presenter tells the view what to display. So in your Perspective you implement those interface functions and in each one you can set up your Perspective in a different way.
For each View it goes in the same way, you will need a presenter for the view which performs operations and tells the view (using the interface) what to display and passing down the final data. The view doesnt care about the logic. This is also very usefull when using JFace-Databindings (then only bound data is passed to the view).
For example, the WorkbenchWindowAdisor will just create everything that is needed in the application. Other views, perspectives, then can enable/disable menus and so on depending on the data they got (like when isAdministrator you might want to enable an special adminMenu).
I know this is quite a heavy approach, but the Eclipse RCP is designed for big (as the name says rich) applications. So you should spend some time in the right architecture. My first RCP app was like you described...I never knew where to store things and how to handle all the references. At my work I learned about MVP (and I am still learning). It takes a while to understand the concept but its worth it.
You might want to look at my second post at this question to get another idea on how you could structure your plugins.
Related
I'm working on a game (in Unity3D) which consists of a dozen menus and no real 2d/3d game world. From a programmer's perspective it is just a bunch of buttons, labels and images.
To not have everything inside of one big menu class, I decided to split the code in parts for every menu. The result is that I've got a dozen classes which themselves have all the references to their gameobjects and e.g. the button methods.
My problem is that almost everything in my project is static by now, because these menus do not get instantiated multiple times and I have to access variables and methods from one menu with the script of another menu.
Thus my question is what the best practice would be for this situation. I've got a couple of ideas, how I could do it, but unfortunately I didn't get to learn what to do in such a situation.
So if you straight up want to suggest something, feel free to do so. :)
My ideas:
1) Make a controller which has static instances of all menus. A button-method in class 'A' could then call Controller.B.x. This does work, but I dislike putting "Controller" everywhere so often, because most classes access methods and variables from other classes so often, that it's just ugly.
2) Make these menus all be singletons. Afaik are singletons "ok" for something like this, but aren't they just shifting the static instance to their own class instead of one controller? When I switched from option 1) to this with one class, basically Controller.A.x became A.instance.x, where "instance" is the static instance of the class inside the class.
3) Keeping everything the way it is, having variables and method being static whenever I need to access them statically from another class, otherwise make them private.
The game is probably not a "bunch of buttons, labels and images".
I suggest to forget about the menus for a second, focus on the model of your game, create classes strictly for that. You don't put things like "how much of a currency does the player have" in any menu, it should exist in a Player class or similar (the model).
Once you can manipulate your model from a single test controller class, and simply log the results in debug console, you're ready to do the same with menus.
After that, you can much easily create user interfaces to read /display (creating labels and images on the fly) and write (hook button events into) the model beneath. These UI classes will probably have so much in common after that.
You can use UnityEvent class for communication between UI and model, they are nicely shown in the Inspector (the same events used in UI Events and Event Triggers).
Fore more general info, Google on some design patterns like MVC, MVP, MVVM, or VIPER.
My recommendation is to strongly consider why you have statics. I understand your reasoning that they are singletons but I don't think that is a good enough reason.
I hope you are using the Unity GUI features properly.
I would just write a base "Menu" component. Then you can add references into the sub classes. For example.
You have a "StartMenu" class derived from "Menu" which is derived from "MonoBehavior". In "StartMenu" you write a method "ShowCharacterCreationMenu()". Then add a button component and hook the method up to that button press. StartMenu will have to have a reference to Character menu. This is the classical OOP approach.
I would do this a little differently though. Unity's strength lies in component based design so I would lean towards that. I would probably create a "Transition" component class that listens for a button press. When that button is pressed it goes to the next menu.
Hope that makes some sense.
https://github.com/brianchance/MvvmCross-UserInteraction is a very nice plugin for showing cross platform Alerts!
But for this question, can we assume it can not use a UIAlertView (or some other top level MessageBox type call on other platforms) but needs to show a Message within a given subsection of the screen (i.e. on IPhone you would need to supply a UIView to the plugin which it will use to show the message within).
So, how would you set this up so the ViewModel knows what View to use as its display container?
As a specific example, if I wanted an Error Service, as so -
public interface IErrorPFService
{
void Show();
void Hide();
void SetErrors(List<Error> errors);
}
and I create a platform specific implementation for it.
If I inject this into my ViewModel so it can control Error Show/Hide/Set how do I tell it the UIView (or equivalent) that I want my Errors to show within?
Can I just expose the IErrorPFService field as a public property and do -
MyViewModel.ErrorPFService = new ErrorPFService(View);
in my ViewDidLoad ...
Or is this coupled incorrectly vs Mvvm Practice?
I would expect the ViewModel to subscribe itself to the ErrorService.
When receiving a message it would expose it in a collection(?) and the View would bind to that collection.
This way the View is unknown to the service and the ViewModel has the chance to influence the View contrary to your solution.
It would help if you could give an example for the scenario you are describing.
Sometimes, the way you visually want to display something might not be the best way, so if it's possible for you, you might find a different and simpler way, which spares you from having to find a solution regarding what you are describing.
Generally, I always do the best I can to avoid the idea of having to actually pass a 'view' or an abstraction of it, from the view-model to view. Also, cross-platform wise, things can work very different in terms of UI interaction. You can find yourself in a situation when things are complicated just because UI works differently than what you expected.
But let's try find another perspective:
At any given point, the view knows what data \ feature it's displaying. So when you are calling from the view-model an user interaction action (by a service, property change, event, etc) the view should 'expect' it.
For example, the platform specific user interaction implementation is able to get the currently displayed top-view and interact it in a platform specific manner or based a relationship. In your example, the message-box can be displayed in a specific sub-view of the top level view.
In advanced scenarios, I guess you could try to create a cross-platform approach for this, but you should try to put in balance all the abstraction you want to create just for that. Think about doing this as a plan ... Z. If possible. Again, giving an example might help.
Lets say that on all my views, or generally at any time in my app, I want to be able to show an error message popup, and it always looks the same. How do I do that?
First thought is having all my view models extend a base view model which facilitates these things, but after that, do I have this base view model actually create the UI widgets and display them?
thanks,
Mark
If you've got some common functionality that you want to provide across a range of views, then you can implement a base class that inherits from the PhoneApplicationPage, and then derive all your classes from that class instead. The XAML for your pages then looks like this:
<local:BasePage xmlns ...
xmlns:local="clr-namespace:MyNamespace"
x:Class="MyNamespace.MyPage">
However, you will not be able to define common UI components in the XAML for your base page. If you wanted to have common UI components you would have create them manually in the code-behind for the base page, perhaps in a handler for the Loaded event, but I think a better solution would be to provide your common UI in a UserControl, which you then add to each of your pages.
If you want to show a Toast or Message Box, then I would recommend the ToastRequestTrigger and MessageBoxRequestTrigger from the Silverlight Toolkit as described in the patterns & practices WP7 Developer Guide.
you could probably define an event on base view model, which is fired inside view model whenever an error occurs, then in view, you can subscribe to this event and display the popup. You can carry error context in EventArgs of the fired event.
Additionally you could unify the logic for displaying the popup but that's probably another story :)
This is testable and nicely decoupled from the view.
Hope this helps,
Robert
Having worked with .net in both winforms and ASP.net for a few years I am now starting to get into MVC (a little late I know). One major confusion for me is the concept of reusable 'components', similar to the concept of a usercontrol in webforms.
For example, I would like to have a number of 'widgets' within the members area of my site, one of which is the details of the logged in users account manager. I can create this as a partial however when the page loads the data needs to be passed in as part of the ViewModel / View Data. I would like to use this widget in a number of different sections which would then mean that I need to put the code to pass the data in into a number of different controllers. This seems to violate the DRY principle, or am I missing something here? I would ideally like everything to be encapsulated within the 1 partial which can then be used in any page.
You can go three ways:
1) For simple controls without much logic, you can create new instance of the custom view model for the control:
Html.RenderPartial("YourControl", new YourControlViewModel () { Param1="value1", Param2 = Model.AnotherValue });
2) If you need some back end logic for the control, you can use
Html.RenderAction("ActionName", "SomeControllerName", RouteValuesDictionary);
It will call standard controller action, use the view, and insert the resulting output back to the page. You can add [ChildActionOnly] atribute to the controller method to ensure that the method will be available only from the Html.RenderPartial. It is slightly violating the MVC principle (view shouldn't call controller), but its great for widgets, and it is used in the Ruby on Rails world without much issues. You can check great article from Haacked
3) Create custom html helper for tasks like custom date formatting, calculating etc..
In your case, I would choose the number two.
I'm a little confused about MVVM.
I understand the concept and can see the advantages. My problem is: does the ViewModel pass data directly from the model.
For example, let's say I have a "User" model with a findByName() method. The ViewModel would call this in order to pass
the relevant user details to the view.
The model would likely retrun a set of "User" objects each which has properties such as name, email address etc and may also have methods.
My question is, should the ViewModel return the set of User objects to the view, or return a restructured version of this which
contains only what the view needs?
As I understand it, the "User" object in this case is part of the model layer and in MVVM the View should be dependant only on the ViewModel.
My issue with this is the ammount of seemingly redundant binding logic required in the ViewModel that would be created to restructure the output.
Passing the set of User objects directly to the View (via the ViewModel) would be far simpler.
There's a little bit of redundancy, sure. However, if you implement MVVM by presenting the objects, you get to
format the model information for the view without polluting the model with presentation logic
notify the view when anything changes
use WPF's validation (if you're using WPF)
run acceptance tests from the VM level rather than the GUI if you want to
abstract your presentation away from any changes to the model.
That last one's important. Mostly presentation bindings nowadays are dynamic and fail silently - web pages, WPF, you name it. That means that if someone decides to rename something on the model, it will suddenly break in your GUI and you won't know.
By putting a VM between your Model and View you buffer yourself from changes like this.
If you want to go ahead and get something working with the Users as they are, I say go for it - it'll help you get fast feedback on your GUI. However, the first time those User objects don't do exactly what the View needs, or you need to notify the View of a change, or you find yourself polluting the model, or something in the binding breaks, maybe that's a good time to move to MVVM.
Doesn't that just move the break to the ViewModels which are using the model? You'd still need to go through and update all of those.
If I renamed something (e.g. changed "surname" to "lastname") I'd expect things to break. I don't see how adding the binding in the VM layer fixes that.