I am building a winforms screen. On the screen, it will show
Category1
Sub-1-1
Sub-1-2
Sub-1-3
Category2
Sub-2-1
Click on the sub-1-1 will popup an screen and show the data related to sub-1-1; same for sub-1-2, ... etc. So there will be totally five forms (1 main form + 4 popup forms for the sample above (the actually will have about 30 sub categories)).
I have models for Categories, sub-1-1, sub-1-2, ..., sub-2-1. I am writing a service layer. Should I do,
public class ServiceLayer
{
CategoriesModel GetCategories();
Sub11Model GetSub11();
Sub12Model GetSub12();
Sub13Model GetSub13();
Sub21Model GetSub21();
.....
}
Or each form has its now service class instance?
public class ICategoryService { ... }
public class ISubCategoryService<T>
{
T GetSub();
}
var sub11 = new SubService<Sub11Model>();
var sub12 = new SubService<Sub12Model>();
var sub13 = new SubService<Sub13Model>();
var sub21 = new SubService<Sub21Model>();
....
The first one looks like a GOD class and will probably violate most of the SOLID principles. It will make the code hard to refactor, even if it's just a facade.
You should of course use smaller interfaces which is only handling one responsibility.
Related
In this example, a unique Person is defined by their FirstName and LastName. PageA is a form that selects a unique Person. PageB is a list of unique FirstNames, and PageC is a list of all the LastNames that exist for a given FirstName.
I'm having a hard time solving a particular UX pattern using MvxNavigationService. Here's what I'm attempting to do, (psuedocode):
PageA.SelectedItem = NavigateTo(PageB) [list of Person, grouped
by Person.FirstName];
PageB.SelectedItem = NavigateTo(PageC) [for
Person.FirstName, list of Person.LastName, ];
PageC.Close(SelectedItem);
PageB.Close(SelectedItem);
When I actually try and implement this and run it on Android, the viewmodel logic executes, but the UI doesn't show PageA.
Update: Calling PageB.Close() navigates back to PageC, since PageC was the previous page. Perhaps the problem could be solved by ensuring that PageC is removed from the stack upon closing it. How might this be accomplished?
There's many ways of doing this, using a Custom ViewPresenter on iOS or using an Activity on Android.
One way I achieved this for a small pair (2 view models) was by adding an Instance static variable to the first ViewModel that opens the second ViewModel, like this:
public class FirstViewModel
{
public static FirstViewModel Instance;
public void FirstViewModel()
{
Instance = this;
...
}
}
And then in the second ViewModel's save/close command, I just closed both ViewModels like this and it worked:
public new MvvmCross.Commands.IMvxCommand SaveClickCommand
{
get
{
return new MvvmCross.Commands.MvxAsyncCommand(
async () =>
{
await Navigator.Close(this);
await Navigator.Close(FirstViewModel.Instance);
}
);
}
}
I have combed through SO, and have found many questions on the topic of my problem but do not answer it.
I am setting up an MVC, I have set up things correctly to best of my knowledge but I cannot get the Controller to show in my view. I am working on an assignment that essentially is a program for a Video Rental Store.
First, In a class called RentalStoreGUI, I set up my panels and everything looks good when I run.
RentalStoreEngine model = new RentalStoreEngine();
JList<DVD> list = new JList<DVD>();
list.setModel(model);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setVisible(true);
list.setSelectedIndex(0);
jScrollPane = new JScrollPane(list);
add(jScrollPane, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
As you can see I set my model for the list based on another class called RentalStoreEngine() and it implements AbstractListModel. The Abstract List model is functioning when I do class specific testing and all of the necessary methods are implemented. Here is an example of my add method from that class:
public void add(DVD d){
if (d != null){
rentals.add(d);//rentals is an arrayList<DVD> instantiated earlier
fireIntervalAdded(this, rentals.size() - 1, rentals.size() - 1);
}
}
Here is the actionPerformed method, it runs DVD_Dialog which simply gets some input from the user and creates a new DVD object from that.
public void actionPerformed(ActionEvent event) {
if(event.getSource() == rentDVD){
DVD_Dialog = new RentDVDDialog(this, null);
DVD_Dialog.clear();
DVD_Dialog.setVisible(true);
dvd = new DVD(DVD_Dialog.getTitleText(),DVD_Dialog.getRenterText(),
DVD_Dialog.getRentedOnText(), DVD_Dialog.getDueBackText());
if(DVD_Dialog.closeStatus() == true){
model.add(dvd);
}
}
Eclipse gives me no errors, until I run it. I then receive a nullPointerException at the line model.add(dvd); Based on all my research the list.setModel(model) and the fireIntervalAdded method line should update the Jlist on its own. But it does not. And as I said, class specific testing for both the GUI and the Model are producing the desired results, but when it comes to integrating them I am at a loss.
I have been using MvvmCross on a cross platform mobile project and have 2 different views in a MonoTouch project that are using the same shared viewmodel and not sure how to go about structuring my code to navigate to different views using the same viewmodel in MvvmCross.
The default convention used by the MvvmCross platform is to automatically register all views using reflection.
This is done in the base Setup class - in https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross/Platform/MvxBaseSetup.cs:
protected virtual void InitializeViews()
{
var container = this.GetService<IMvxViewsContainer>();
foreach (var pair in GetViewModelViewLookup())
{
Add(container, pair.Key, pair.Value);
}
}
where GetViewModelViewLookup returns a dictionary of ViewModel type to View type:
protected virtual IDictionary<Type, Type> GetViewModelViewLookup(Assembly assembly, Type expectedInterfaceType)
{
var views = from type in assembly.GetTypes()
let viewModelType = GetViewModelTypeMappingIfPresent(type, expectedInterfaceType)
where viewModelType != null
select new { type, viewModelType };
return views.ToDictionary(x => x.viewModelType, x => x.type);
}
In universal iPad/iPhone apps you do occasionally want to include multiple views for each viewmodel - using one view in the iPad and one view in the iPhone.
To do this, there are now (literally just now!) some attributes available to mark your views as being "unconventional" - these are:
MvxUnconventionalViewAttribute
use this to mark that your view should never be included by convention
in https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross/Views/Attributes/MvxUnconventionalViewAttribute.cs
MvxConditionalConventionalViewAttribute
an abstract attribute - override this to provide your own custom logic for inclusion/exclusion
in https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross/Views/Attributes/MvxConditionalConventionalViewAttribute.cs
MvxFormFactorSpecificViewAttribute
iOS/Touch only
an attribute that will include the view if and only if the detected iPhone form factor matches the current device
in https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross/Touch/Views/Attributes/MvxFormFactorSpecificViewAttribute.cs
The last of these is probably what you want in this case - you could implement simple iPhone/iPad switching for a MainViewModel using two views declared like:
[MvxFormFactorSpecificView(MvxTouchFormFactor.Phone)]
public class MyIPhoneView : BaseView<MainViewModel>
{
// iphone specific view ...
}
[MvxFormFactorSpecificView(MvxTouchFormFactor.Pad)]
public class MyIPadView : BaseView<MainViewModel>
{
// ipad specific view ...
}
Alternatively if you want a very custom configuration, you can override all 'convention-based' behaviour - you can implement your own override of GetViewModelViewLookup - e.g.:
protected override IDictionary<Type, Type> GetViewModelViewLookup(Assembly assembly, Type expectedInterfaceType)
{
if (IsIPad)
{
return new Dictionary<Type, Type>()
{
{ typeof(HomeViewModel), typeof(IPadHomeView) },
{ typeof(DetailViewModel), typeof(IPadDetailView) },
{ typeof(AboutViewModel), typeof(SharedAboutView) },
};
}
else
{
return new Dictionary<Type, Type>()
{
{ typeof(HomeViewModel), typeof(IPhoneHomeView) },
{ typeof(DetailViewModel), typeof(IPhoneDetailView) },
{ typeof(AboutViewModel), typeof(SharedAboutView) },
};
}
}
Note that eventually you may decide that you need additional ViewModels as well as Views for the iPad app - the iPad has, after all, a much bigger screen - in this case you can add them manually. Ultimately, when your app hits a few million users, you may even decide to completely branch the tablet code away from the phone code - but that can generally wait until you hit that few million mark...
Another way to do it is to go ahead and create 2 ViewModels, but have them both subclass an abstract ViewModel, as follows:
FirstViewViewModel : BaseViewModel
SecondViewViewModel : BaseViewModel
With the corresponding views named:
FirstView.xaml
SecondView.xaml
This way, you are able to place some shared behavior in BaseViewModel, while the 2 subclasses are really just there to satisfy MvvmCross' view fetching conventions.
I recently started with MvvmCross and I am using v4.2.1. It seems that some names have changed. I am using one ViewModel with seperate iPhone and iPad views with the following:
[MvxFormFactorSpecific(MvxIosFormFactor.Phone)]
public class MyIPhoneView : BaseView<MainViewModel>
{
// iphone specific view ...
}
[MvxFormFactorSpecific(MvxIosFormFactor.TallPhone)]
public class MyTallIPhoneView : BaseView<MainViewModel>
{
// tall iphone specific view ...
}
[MvxFormFactorSpecific(MvxIosFormFactor.Pad)]
public class MyIPadView : BaseView<MainViewModel>
{
// ipad specific view ...
}
Basically I want to set 20 or so Request.Form values, send a POST to my controller, and then check the result.
I found a couple articles such as this one which describe how you can do this with a combination of NUnit, MVCContrib, and Rhino Mocks. But I don't know if this is truly necessary.
It would seem that Visual Studio 2010 and ASP.NET MVC 2 should be able to do this natively and display the results in the little "Test Results" window. In fact, when I create a new unit test with the wizard, it comes up with this...
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("G:\\Webs\\MyWebsite.com\\MyWebsite", "/")]
[UrlToTest("http://localhost:43383/")]
public void PaypalIPNTest()
{
BuyController target = new BuyController(); // TODO: Initialize to an appropriate value
ActionResult expected = new EmptyResult(); // TODO: Initialize to an appropriate value
ActionResult actual;
actual = target.PaypalIPN();
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
Is it possible to feed target.PaypalIPN() my Request.Form variables based on the above code? Or do I need to rely on 3rd party libraries to get this done?
In fact, when I create a new unit test with the wizard, it comes up with this
Yes, and all that you can keep from this is the method signature. The method body is useless.
So let's start by looking at this:
Is it possible to feed target.PaypalIPN() my Request.Form variables
By reading this sentence I assume that your controller action looks something like this:
[HttpPost]
public ActionResult PaypalIPN()
{
string foo = Request["foo"];
string bar = Request["bar"];
... do something with foo and bar
}
So the first is to improve this code by introducing view models:
public class MyViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
and then modify your method signature to:
[HttpPost]
public ActionResult PaypalIPN(MyViewModel model)
{
... do something with model.Foo and model.Bar
}
Now your controller is abstracted from any HttpContext infrastructure code (which really should be left to the framework, it is not your controller actions responsibility to read request parameters => that's plumbing code) and unit testing it is really a simple matter:
[TestMethod()]
public void PaypalIPNTest()
{
// arrange
var sut = new BuyController();
var model = new MyViewModel
{
Foo = "some foo",
Bar = "some bar",
};
// act
var actual = sut.PaypalIPN(model);
// assert
// TODO:
}
OK, this being said, here we dealt with some really simple controller action. For more advanced scenarios you really should consider using a mocking framework. Personally I use MvcContrib.TestHelper with Rhino Mocks to unit test my ASP.NET MVC applications.
I have another approach to test my MVC application, first I used Dev Magic Fake to fake any underline layer under the controller until the application is running and the business is approved and then I replace the fake code with TDD approach based on approved requirements
See Dev Magic Fake on CodePlex:
http://devmagicfake.codeplex.com/
Thanks
M.Radwan
I'd like to pair a Model with it's View through an interface. I want to control when and how often the view is updated. So something like PropertyChangeListener wouldn't work well (where an event is fired after each property is set).
I'm not developing for a specific GUI framework. The goal here is the ability to swap out different GUI front ends (right now for testing, but might be useful later for different versions of the app). These might be Swing, or it might be a web browser (via GWT, for example).
Below is my approach. The view implements an interface to provide a method to update. This is triggered by the controller when it determines it's done updating the model. This still feels ok to me, since the Controller is only interacting with the view through the model, the controller is not dependent on a particular implementation of the View.
So, I guess my question(s) are
does this work well?
Is this standard practice?
Does this pattern have a name?
Rough code sample (Java):
// Controller, manages Items (the model)
class ItemList {
void addItem(Item item) {
}
void doStuffWithItems() {
// perform some set of operations, such as sorting or layout
for (Item item : items) {
// ....
}
// now with everything in it's final position:
for (Item item : items) {
item.updateView();
}
}
}
// Model
class Item {
private int top;
private int left;
private int width;
private int height;
// Can remember it's previous position/size:
public void savePostion() {
}
// And recall it for the Controller to use:
public public Position getSavedPosition() {
}
// Plus some other useful functions:
public boolean intersectsWith(Item other) {
}
public void updateView() {
this.view.update();
}
void setView(ItemView view) {
this.view = view;
}
}
// Interface used by View implementations
public interface ItemView {
// Trigger the view to reflect the current state of the model
void update();
}
// Example, as a Swing component
class ItemComponent extends JComponent implements ItemView {
private Item item;
public ItemComponent(Item item) {
this.item = item;
item.setView(this);
}
// ItemView#update
public void update() {
// update the component's size/position
setBounds(new Rectangle(item.getLeft(), item.getTop(), item.getWidth(), item.getHeight()));
}
#Override
public void paint(Graphics g) {
// ...
}
}
I would avoid forcing the View to implement an interface only for change notification. Create a separate "update now" event on the model instead.
The model should not be controlling or know about the view directly. The view should register a callback with the controller so the controller can tell the view when to update, that's why its the controller. You could have the model allow external listeners for a modelChangedEvent. Then the view could register with the model in that respect without the model knowing there was a view. See the J2EE blueprint for MVC and how there is an indirect event notification of state change in the model.
For traditional applications that run on the desktop of a computer I recommend variants of the Passive View. The class responsible for creating and managing the form is a thin shell that passes events to the UI Object. The UI_Object interact with the form via a interface. In term the UI Object implements a UI_View Interface and registers itself with a View Controller that is situated lower in the object hierarchy.
The UI_Object then execute object implementing the Command Pattern which modifies the model. The command object can interacts with the various views via the interfaces exposed by the View Control.
What this does is allow you to rip off the form classes and replace them with stub classes that implement the form interfaces. The stub classes are used for automated testing especially for integration tests.
The interfaces precisely define the interaction between the Form, the UI_Object, Commands and the views. They can be designed to be relatively language agnostic so they can make porting between platform easier.
What you are missing in your example are command objects. You need this structure
ItemViewForms
ItemViewImplementation
ItemViewFormInterface
ItemViewCommands
ItemViewInterface
MyModel
Incorporate ItemList in the ItemViewImplementation
ItemComponent would register with the ItemViewImplementation using the ItemViewInterface.
The sequence of events would look something like this
User wants to update the Item
Clicks on the UI (assuming that UI
involves clicking with a mouse)
The Form tells the
ItemViewImplementation through the
ItemViewInterface that X has been
done with Y parameters.
The ItemViewImplementation then
creates a command object with the
parameters it needs from Y.
The Command Object take the Y
Parameters modifies the model and
then tells the
ItemViewImplementation through the
ItemViewInterface to update the UI.
The ItemViewImplementation tells the
ItemViewForms to update the UI
through the ItemViewFormInterface.
The ItemViewForms updates.
The advantage of this approach is that the interaction of each layer is precisely defined through interfaces. The Software ACTIONS are localized into the command objects. The Form layers is focused on display the result. The View layer is responsible for routing actions and response between the Commands and Forms. The Commands are the only things modifying the model. Also you have the advantage of ripping off the Forms Implementation to substitute any UI you want including mock object for unit testing.