Register a single View as the View for Multiple ViewModels - MVVMCross - mvvmcross

MMVMCross
Android
Windows 8
We had a View, call it FruitView displaying a ViewModel called FruitViewModel. The FruitViewModel can display lists of a particular type of fruit.
This all worked fine.
For a couple of reasons we created AppleViewModel and PearViewModel that inherit from FruitViewModel. They do not do anything, all calls are made to the base viewmodel.
I want to register the FruitView as the View for AppleViewModel and PearViewModel when I try and navigate to them using MvxNavigatingObject.ShowViewModel.
I cannot see how to override the default linking of Views to ViewModels. I read one post that suggested overriding GetViewModelViewLookup in the Setup class but that does not seem to exist. I also looked at CustomPresenters but that did not look like the right approach.
Anyone else done this?
Thanks
Pat

After spotting this question How to navigate to a ViewModel that extends an abstract class? (not one of the suggesting when i was posting) I found InitializeViewLookup that can be overridden in each platform's Setup.cs. I am augmenting the current mappings rather than replacing so have called base.InitializeViewLookup first.
protected override void InitializeViewLookup()
{
base.InitializeViewLookup();
var viewModelViewLookup = new Dictionary<Type, Type>()
{
{ typeof(AppleViewModel), typeof(FruitView) },
{ typeof(PearViewModel), typeof(FruitView) }
};
var container = Mvx.Resolve<IMvxViewsContainer>();
container.AddAll(viewModelViewLookup);
}
Thanks
Pat

Related

Add components based on string variables in Blazor

We're creating a dynamic page of components in Blazor. The intention is to have dynamic applets displayed on a page. The idea is that we have a list of strings which correspond to Component names. We read through the string list and for each one, instantiate a blazor component or render fragment. These are just simple components, no passed in parameters or the like. ie:
string[] componentsStrings = {"Component1", "Component2"};
Expected output:
<Component1 />
<Component2 />
We can't come up with a way to do this. It seems like a fairly standard thing to do, but perhaps not? Does anyone know if this is even possible?
You will have to programmatically create a component which adds your custom components on the page using RenderTreeBuilder.
Chris Sainty has a blog post on this which you can read here: https://chrissainty.com/building-components-via-rendertreebuilder/
Basically there is an override for BuildRenderTree in the ComponentBase class which can be used:
public class Menu : ComponentBase
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "nav");
builder.AddAttribute(1, "class", "menu");
}
}
Here is another tutorial.
Some tips from here:
Place base.BuildRenderTree(builder); at the start of the
BuildRenderTree method , not at the end.
Always start with the value 0 for the sequence parameter.

Android ListView binding programmatically

There are many examples of doing this in axml, but I would like to have a complete binding using code behind. To be honest, I would like to have NO axml, but seems like creating all the controls programmatically is a nightmare.
I first tried the suggestions at:
MvxListView create binding for template layout from code
I have my list binding from code-behind, and I get six rows (so source binding is working); but the cells itself does not bind.
Then at the following url:
Odd issue with MvvmCross, MvxListViewItem on Android
Stuart has the following comment: Have looked through. In this case, I don't think you want to use DelayBind. DelayBind is used to delay the binding action until next time the DataContext is set. In Android's MvxAdapter/MvxListItemView case, the DataContext is passed in the ctor - so DataContext isn't set again until the cell is reused. (This is different to iOS MvxTableDataSource).
So in essence, the only example I see shows DelayBind, which shouldn't work.
Can someone please show me some examples... thanks in advance.
Added reply to Comments:
Cheesebaron, first of all, a huge thank you and respect for all your contributions;
Now, why not use axml? Well, as programmers, we all have our own preferences and way of doing stuff - I guess I am old school where we didn't have any gui designer (not really true).
Real reasons:
Common Style: I have a setup where Core has all the style details, including what all the colors would be. My idea is, each platform would get the style details from core and update accordingly. It's easy for me to create controls with the correct style this way.
Copy-Paste across platform (which then I can even have as linked files if I wanted). For example, I have a login screen with web-like verification, where a red error text appears under a control; overall on that screen I have around 10 items that needs binding. I have already got iOS version working - so starting on Droid, I copied the whole binding section from ios, and it worked perfectly. So, the whole binding, I can make it same across all platform... Any possible error in my way will stop at building, which I think is a major advantage over axml binding. Even the control creation is extremely similar, where I have helpers with same method name.
Ofcourse I understand all the additional layout that has to be handled; to be honest, it's not that bad if one really think it through; I have created a StackPanel for Droid which is based on WP - that internally handles all the layouts for child views; so for LinearLayout, all I do is setup some custom parameters, and let my panel deal with it. Relative is a different story; so far, I have only one screen that's relative, and I can even make it Linear to reduce my additional layout code.
So, from my humble point of view, for my style, code-behind creation allows me to completely copy all my bindings (I do have some custom binding factories to allow that), copy all my control create lines; then only adding those controls to the view is the only part that is different (then again, droid and WP are almost identical). So there is no way I can miss something on one platform and all are forced to be the same. It also allows me to change all the styles for every platform just by changing the core. Finally, any binding error is detected during compile - and I love that.
My original question wasn't about NOT using axml... it was on how to use MvxListView where all the binding is done in code-behind; as I have explained, I got the list binding, but not the item/cell binding working.
Thanks again in advance.
Here is part of my LoginScreen from droid; I think it's acceptable amount of code for being without axml file.
//======================================================================================================
// create and add all controls
//======================================================================================================
var usernameEntry = ControlHelper.GetUITextFieldCustom(this, "Username.", maxLength: 20);
var usernameError = AddErrorLabel<UserAuthorization, string>(vm => ViewModel.Authorization.Username);
var passwordEntry = ControlHelper.GetUITextFieldCustom(this, "Password.", maxLength: 40, secureTextEntry: true);
var passwordError = AddErrorLabel<UserAuthorization, string>(vm => ViewModel.Authorization.Password);
var loginButton = ControlHelper.GetUIButtonMain(this);
var rememberMe = new UISwitch(this);
var joinLink = ControlHelper.GetUIButtonHyperLink(this, textAlignment: UITextAlignment.Center);
var copyRightText = ControlHelper.GetUILabel(this, textAlignment: UITextAlignment.Center);
var copyRightSite = ControlHelper.GetUIButtonHyperLink(this, textAlignment: UITextAlignment.Center);
var layout = new StackPanel(this, Orientation.Vertical)
{
Spacing = 15,
SubViews = new View[]
{
ControlHelper.GetUIImageView(this, Resource.Drawable.logo),
usernameEntry,
usernameError,
passwordEntry,
passwordError,
loginButton,
rememberMe,
joinLink,
ControlHelper.GetSpacer(this, ViewGroup.LayoutParams.MatchParent, weight: 2),
copyRightText,
copyRightSite
}
};
I just came across a similar situation myself using Mvx4.
The first link you mentioned had it almost correct AND when you combine it from Staurts comment in the second link and just remove the surrounding DelayBind call, everything should work out ok -
public class CustomListItemView
: MvxListItemView
{
public MvxListItemView(Context context,
IMvxLayoutInflater layoutInflater,
object dataContext,
int templateId)
: base(context, layoutInflater, dataContext, templateId)
{
var control = this.FindViewById<TextView>(Resource.Id.list_complex_title);
var set = this.CreateBindingSet<CustomListViewItem, YourThing>();
set.Bind(control).To(vm => vm.Title);
set.Apply();
}
}
p.s. I have asked for an Edit to the original link to help others.

How to mock a CQ5 Page object containing a cq5 tag

I have a method on which I'd like to run a JUnit test. I'm mocking the cq5 page using JMockit.
My test method looks like this
#Mocked
Page page;
#Mocked
PageManager pageManager;
Tag testTag = pageManager.createTag("someID","someTitle","someDescription");//i've left out the try catch for brevety
System.out.println(testTag.getTitle()); // always null here
public void testSomeMethod() {
new Expectations() {
// variables declared here are mocked by default
{
page.getProperties();
propertyMap.put("cq:tags", testTag);
returns(new ValueMapDecorator(propertyMap));
}
};
String propertyValue = methodToBeTested(page);
Assert.assertEquals(propertyValue, "someTitle");
}
And the actual method to be tested does this :-
public static String getTopic(Page page) {
String topic = null;
Tag[] tags = page.getTags();
System.out.println(tags.size()); // returns 0 when I run the test.
for (int i = 0; i < tags.length; i++) {
Tag tag = tags[i];
topic = tag.getTitle();
}
}
return topic;
}
This always returns null when I run the test; however the method to be tested works correctly in the real scenario.
I suspect I'm not setting/mocking PageManager correctly, and consequently, my testTag is null
How do I mock this correctly to get the output I'm looking for?
You're getting to this testing from the wrong side. The way mocks (usually - I've never worked with jmockit specifically) work is, you create a blank object that acts as an impostor. This impostor is not a true PageManager - it only acts as one, and introduces himself as one whenever asked. When someone asks that impostor to do something (like calling it's method), the impostor does not know what to do, so it does nothing and returns null. However, you can tell the impostor how to behave in certain situations. Namely, you can tell it what to do when a method is called.
In your case, you don't need to create actual tags to test that method - you only need to mock a page object that, when asked for it's tags, will return an array containing a mocked tag which, in turn, when asked for it's title, will respond with the title you actually want to use in your test.
I don't know jmockit, so I cannot provide any code snippet. This, however, is a general question not strictly connected to CQ5/AEM
You may not be able to find any 'setter' methods for all objects you are trying to mock and this is anyways not the correct approach to mock.
The best way as mentioned by is to use mocked pages. You can use the Expectations class (mockit.Expectations) to mock the values to be returned by certain methods in the object.
See this example of mocking a 'SlingHttpServletRequest' object in a MockedClass class.
#Test
public void testMethod(#Mocked final SlingHttpServletRequest request){
String indicator ;
new Expectations() {
{
request.getParameter("archive");
returns("true");
}
};
indicator = OriginalClass.originalMethod(request);
Assert.assertEquals(indicator, "true");
}
In a similar way, you can mock other objects and their desired values.
I have answered the same question here: https://forums.adobe.com/thread/2536290
I ran into the same issue. in order to resolve Tags, they must exists under /content/cq:tags/your/tag or /etc/tags (legacy).
The Page#getTags implementation makes a call to TagManager#getTags which in turn tries to resolve the actual tag resource in the repo. Since you are testing in an AEM context, you have to load these tags in the appropriate location for the MockTagManager to resolve them.
What this means is that you need to load your tags into the AEM test context just like you've loaded your resources (via json).
Take a look at the aem-mock TagManager impl here: wcm-io-testing/MockTagManager.java at develop · wcm-io/wcm-io-testing · GitHub start with the resolve method and debug your way to figure out where you need to add those tags.

MVVMCross - display view inside view

I cannot seem to find any simple examples of this.
I have a WPF UI that I wish to display a view as a child control within another view. The MvxWpfView inherits from UserControl so it should be possible, however I cannot seem to work out how to do the binding.
I get a BindingExpression path error, as it cannot find ChildView property in my ParentViewModel.
So how do I bind a view to control content?
Firstly it's possible that you just need to add the BViewModel you want displayed on AView as a property on ViewModelA
E.g.
public class AViewModel: MvxViewModel
{
public BViewModel ChildViewModel
{
get;set;//With appropriate property changed notifiers etc.
}
}
Then inside AView you just add a BView, and you can set the datacontext of BView as follows:
<UserControl DataContext="{Binding ChildViewModel}"/>
However, if you want something more flexible (and you want the presentation handled differently for different platforms) then you will need to use a Custom Presenter
Inside your setup.cs you override CreateViewPresenter:
protected override IMvxWpfViewPresenter CreateViewPresenter(Frame rootFrame)
{
return new CustomPresenter(contentControl);
}
Now create the class CustomPresenter you need to inherit from an existing presenter. You can choose between the one it's probably using already SimpleWpfPresenter or you might want to go back a bit more to basics and use the abstract implementation
The job of the presenter is to take the viewmodel you have asked it to present, and display it "somehow". Normally that mean identify a matching view, and bind the two together.
In your case what you want to do is take an existing view, and bind a part of it to the second view mode.
This shows how I have done this in WinRT - but the idea is very similar!
public override void Show(MvxViewModelRequest request)
{
if (request.ViewModelType == typeof (AddRoomViewModel))
{
var loader = Mvx.Resolve<IMvxViewModelLoader>();
var vm = loader.LoadViewModel(request, new MvxBundle());
if (_rootFrame.SourcePageType == typeof (HomeView))
{
HomeView view = _rootFrame.Content as HomeView;
view.ShowAddRoom(vm);
}
}
else
{
base.Show(request);
}
}
So what I'm doing is I'm saying if you want me to present ViewModel AddRoom, and I have a reference to the HomeView then I'm going to just pass the ViewModel straight to the view.
Inside HomeView I simply set the data context, and do any view logic I may need to do (such as making something visible now)
internal void ShowAddRoom(Cirrious.MvvmCross.ViewModels.IMvxViewModel vm)
{
AddRoomView.DataContext = vm;
}
Hopefully that makes sense! It's well worth putting a breakpoint in the show method of the presenters so you get a feel how they work - they are really simple when you get your head around them, and very powerful.

Zend Framework a common file to put functions in that can be accessed from a view

I need to have a place to put some common functions that various view scripts will use such as creating some html by passing it a variable. I know about using helpers, but I want to be able to put many functions inside it not just one helper for each function.
Is it a plugin that I need to create?
thanks
A view helper is definitively the way to go. You can group a collection of similar or related functions using a simple design pattern for your view helper:
class App_View_Helper_Example extends Zend_View_Helper_Abstract
{
/**
* #param mixed|null $var
* #return App_View_Helper_Example
*/
public function example($var = null)
{
if ($var === null) {
return $this;
}
return $this->function1($var); // shortcut to method most used
}
public function function1($var)
{
return $this->view->escape($var);
}
public function function2($var1, $var2)
{
return $this->view->escape(sprintf('%s: %d', $var1, $var2));
}
// and so on...
}
This allows you to call your helper methods in your view like this:
$this->example($var);
$this->example()->function1($var);
$this->example()->function2($var1, $var2);
I used this approach for a Google Static Map helper which provides a centered()-method to display a map centered at a given location and a byMarkers()-method that displays a static map automatically centered and zoomed around a list of given markers.
The only problem you may encounter is keeping a state in your helper across different view scripts (e.g. when using layouts or partials) as the helper will be reconstructed with every single view script. To store state across these boundaries you'll have to resort to Zend_Registry or some static member field.
Hm, 'sounds a bit smelly'. What kind of functions would these be? If your design is ok, you shouldn't have a need for this kind of dustbin class. If it is really all about view then you should create view helpers, view partials or partial loops!
Sounds like what you want is the partial helper
If you don't want to use helpers (including the partial helper) you might as well just create some global functions, stick them in some file, and include it from your bootstrap file.
If you don't want a 'bunch of helpers' (which isnt really all that bad, as other posters have suggested), you can extend Zend_View, add the member methods, then set the Viewrenderer to your extended View.
http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.viewrenderer
Thank you all for the suggestions.
I discovered that you can use a view helper (like Stefan said) to store more functions by just returning $this from it like :
class Zend_View_Helper_FormVars
{
public function formVars(){
return $this;
}
public function openFormFieldGroup($name=''){
$html='';
$html.='<div id="formFldGrpWrapper">';
$html.='<div id="formFldGrpName"><b>'.$name.'</b></div>';
return $html;
}
}
Now in my view script I can use it like this:
$formVars=$this->formVars();
$html.=$formVars->openFormFieldGroup('General');
But I'm also interested in what Justin stated that I can have a common extended view helper?
That all my views or controllers can access for doing repetative tasks like some html divs/styles, etc.... How would I go about getting that set up?
thanks.
But I'm also interested in what Justin stated that I can have a common extended view helper? That all my views or controllers can access for doing repetative tasks like some html divs/styles, etc.... How would I go about getting that set up?
In the answers you ask this additional question. My answer deals with that too.
First you need to ask yourselves why you want to have multiple helper functions in one class
One reason is that you saves you extra classes and file includes. How could you do so?
If they are related you can put them into one view helper. But don't do things like
$this->htmlWrapper()->wrapParapgraph()->wrapContentBox()
->translateFromTo('NL', 'EN');
translateFromTo(…) has nothing to with html-wrapping.
If you want to optimize your includes, you can put you common helper code into a derived View-class:
class MyView extends Zend_View
{
function wrapParagraph() {}
function otherFunction() {}
}
This option is also mentioned in the zend framework guide as a means of optimization.
Please note that view helper reusability isn't affected by the choice to create view helpers as separate classes. You automatically get access to the current view oject if your helper extends Zend_View_Helper_Abstract.
class My_View_Helper extends Zend_View_Helper_Abstract
{
function wrapParagraph($content) {
// do something …
return $this->someOtherViewHelper();
}
}
Further you wrote
$formVars=$this->formVars();
This doesn't make sense actualy, since Zend_View registers only one view helper per view isntance.
$formVars=$this->formVars();
$formVars->doOneThing();
$formVars->doSecondThing();
is equivalent to
$this->formVars()->doOneThing();
$this->formVars()->doSecondThing();
The Singleton aspect has a severe impact on the way you design view helpers as you see.