I need to create a Tab view in iOS. I tried to do this by simply adding a UITabBar to an MvxViewController but I could not get that to work (See this question if interested)
I am now trying to go use the approach MVVMCross and Apple seem to push me towards, a TabController.
In our Core project we have 4 ViewModels that are displayed from one or more places using a ShowViewModel call and are initialised with a customerNumber.
CustomerViewModel
CustomerOrdersViewModel
CustomerHistoryViewModel
ReturnsViewModel
In Android and Windows Store we have separate Views for each of these ViewModels. I do not want to change our Core implementation to support iOS. I will create a new ViewModel called TabbedCustomerViewModel and that will have 4 properties, one for each of the hosted ViewModels.
Using a custom MvxTouchViewPresenter registered in the iOS project I can listen for requests to Show one of the Customer views and then switch the Request to TabbedCustomerViewModel. I have that working, the new ViewModel gets created and the initialisation paramaters that would have been passed to the original VM are passed to the intercepting VM's Init method.
The problem I am having is knowing how I should be initialising the hosted VMs. I assume I am going to have to ctor, init and Start them manually. Has anyone got any thoughts on how to do this?
The N-25 Tab Tutorial does not have to worry about this as its hosted VMs are not standalone so don't have Init and Start dependencies
I have the initialisation of the VMs working now too. When the View loads it checks if it is within a Tabbed UI by looking at the ParentViewController.
If it is it calls a custom method on the new TabbedCustomerViewModel. I have copied the code that MVVMCross use and added it to the new Method
try
{
mvxViewModel.CallBundleMethods("Init", this.initialisationParameters);
if (reloadedState != null)
{
mvxViewModel.CallBundleMethods("ReloadState", reloadedState);
}
mvxViewModel.Start();
}
catch (Exception exception)
{
throw exception.MvxWrap("Problem initialising viewModel of type {0}", mvxViewModel.GetType().Name);
}
The initialisationParameters and reloadedState are stored by TabbedCustomerViewModel when it is initialised so that it can pass it down to the ViewModels it is hosting
Related
I have a location mocking method in my main activity. Unfortunately, I cant put this method into another class (yet!). So, I need a service, to call this method from my main activity every 5 seconds. So i created a countdown in within a service that, while the app is in the background, should run the method in my MainActivity. But it doesnt.
public void OnTimedEvent(object sender, System.Timers.ElapsedEventArgs e)
{
Log.Info("2", "CountDown ausgeführt!");
var test = new MainActivity();
test.getMockLocation();
}
This is my code. As you can see, I'm installing a new object of my Main Activity and then ask for the method in within this activity. This does work. Well at least Visual Studio does not complain. If I now debug my app on my phone, nothing happens. I dont get no errors or anything.
Now, when I run this app Step by Step and it reaches this point
"var test = new MainActivity();"
I get "Frame not in Module".
So, it basically crashes as soon as I ask it to install a new object of my Main Activity.
May anybody tell me why this is?
THANKS :)
Unfortunately in Android you cannot create Activities like this, they need to be instantiated by the OS. Also, instantiate a whole Activity only for a method is not ideal, I suggest you to find the way to get that method/function out of that Activity so you can use it anywhere in your program.
Did you create your app via Xamarin Forms? If you did, you can utilize the Xamarin Forms MessagingCenter for background services and then you can call your mock location tasks.
This is the link for a very helpful walk-through and example of MessagingCenter.
I created a new Web API project and created the following routing spec (actually I have simplified, looking for the bug):
// Web API configuration and services
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}"
);
When I make a call via ajax with the route:
/api/account/GetSUID/0
everything works fine. When I just use a different controller:
/api/tile/GetTileSet/0
it returns a status of 200 but instead of hitting my controller, it just returns the contents of the default page in jqXHR.responseText! It is as if it is just skipping any API routing like I am requesting the default site page.
I am baffled by this one as I have written literally hundreds of web API functions over the past few years in several other projects. I have never had any issue making calls to multiple controllers. I have looked high and low for what could be happening here and am hoping that someone here might have an idea.
Here is a sample method on the controller:
[HttpGet]
public HttpResponseMessage CheckRequestedID(int id, [FromUri]string Search)
{
if (!BSDIUtil.HasAllAcceptableCharacters(Search))
return Request.CreateResponse(HttpStatusCode.BadRequest);
if (FolderModel.IDAlreadyExists(DAL, Search)) // We can check this because this function is only called when staff members are creating accounts for other people (participants always use their email).
return Request.CreateResponse(HttpStatusCode.OK, false);
else
return Request.CreateResponse(HttpStatusCode.OK, true);
}
This will work if on the account controller but not on the tile controller.
One other thing, I am using the "Community" edition of Visual Studio and Windows 8.1
This is not a problem that is likely to occur often but I have solved it and figured I would post it here in case anyone else has the same issue.
I am using web api in the context of a standard web forms app (although I am only using webforms for my reporting pages). In the web.config for a web forms app, you can declare the paths that the user has access to before authenticating. I was only providing access to the account controller: all others were not permitted due to my authentication mechanism. Once I authenticate (e.g. the forms authentication call) or if I change the location path to include only "api", the problem goes away.
I was facing same problem but in different context. Had many controllers and respective routing templates. Only one controller was responding to requests.
Later i realized my other controller classes were not public!!
I am using Mvvmcross crosscore in my project
I am trying to bind my loginviewmodel to the loginviewcontroller
I bound a command for the login button. the app waits until it gets a login response, which is stored in the loginViewModel itself..
How can I communicate this to the loginviewcontroller --- regarding the login status and login error message if any
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
What is the best approach to communication any items in the viewmodel back ( I basically mean all the NON-UI binding items)
I am using Mvvmcross crosscore in my project
I'm assuming from this that you followed the CrossLight sample N=39.
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
If you followed N=39. then you can access the DataContext using the property called DataContext - see https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-39-CrossLight-Touch/CrossLightTouch/MyViewController.cs#L33
public object DataContext
{
get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
Beyond this, there are many other examples in the N+1 videos which demonstrate how to communicate between ViewModels and Views including error messages and loading dialogs - e.g. N=34 shows one implementation of progress dialogs - https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-34-Progress
A complete index of N+1 videos is available on http://mvvmcross.wordpress.com
Obviously not all of these are appropriate for your CrossLight approach to development, but this is where you can allow your custom mvvm approach to fill the gap - it's code for you to write in your custom framework.
One of the best methods solving viewmodel interdependencies is using a loosely coupled approch using the MessageBus/Event Aggregator pattern. There's a plugin for MvvmCross. Or you could use the excellent TinyMessenger.
In principle when using this approach, you no longer establish hard references between the publisher and consumers of arbitrary notifications. Instead notifications get published on a message bus and every one is free to listen and subscribe.
I have an ASP.NET MVC 4 site running perfectly well in an Azure WebRole. The ASP.NET MVC project was started on its own, after which I added an Azure Cloud Service project to the solution and added the ASP.NET project/site as one of the 'roles' of the service (so it shows up in the 'Roles' folder).
My problem is that I would like to have working a WebRole.cs file within the ASP.NET MVC project, but no matter what I've tried to do, it appears that when deployed, it just never gets called. OnStart and the override of Run (which I know, must never leave the loop) -- these just apparently never get called.
But if you startup a new CloudService project and add, at that time from the start, an ASP.NET MVC project, it automatically has a WebRole.cs file in it, so my guess is that I need to configure something somewhere for the WebRole.cs (actually speaking, the WebRole class, which inherits RoleEntryPoint) to get called. What might that be?
using System;
using System.Web;
//using Microsoft.WindowsAzure.StorageClient;
using System.Diagnostics;
using System.Threading;
namespace Us.WebUI
{
public class WebRole : Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint
{
public override bool OnStart()
{
return true; //return base.OnStart(); // CALL THIS???
}
public override void Run()
{
while (true) {
Thread.Sleep(TimeSpan.FromSeconds(30));
try {
EmailFuncs.SendEmailToUs("An email from our WebRole?????", "Email me this, email me that.");
}
catch { }
}
}
}
}
UPDATE: Thanks, the question has been answered. But I will add: On doing this, while it clearly was working (fully deployed and in emulator), that suddenly I was having problems doing a full publish of the site. After a azure publish took 3 hours:
Verifying storage account 'xyz'... > Uploading Package... > - Updating... [stayed here for 3 hours], it failed with this error: The server encountered an internal error. Please retry the request. So one thing I was wondering is, did I need to override OnStop in WebRole.cs?
UPDATE 2: Those previous problems were fixed, and had nothing to do with this issue. Actually, I've learned this: If you ever have any warnings generated in your build, Azure often will not work with them even when they don't cause problems locally or in other hosts. Since then, I've been much more studious to tackling build warnings (but critical to this is turning off with warning codes the many warning types you want to ignore!).
Adding a class to your Web Project which inherits from RoleEntryPoint is sufficient, it should just work. Did you try setting a breakpoint in the emulator?
What you might be experiencing is that EmailFuncs.SendEmailToUs requires info from the app/web.config and that this info is not available. You need to know that your WebRole class runs in a different process (not your web application), meaning it's not using your web.config. If you want the WebRole.cs to read info from the configuration file, you'll need to add these settings in WaIISHost.exe.config
I've just upgraded my application to ARC, but I am having issues with how it handles classes with delegates. Because I am targeting iOS 4.0 and above, I am using __unsafe_unretained and #property (unsafe_unretained) to store the delegate pointers.
However, what I am now finding is that the services (that include delegates) I create in my view controllers are now hanging around after I have removed that view controller, which result in trying to communicate back with the view controller (delegate) after it has been deallocated... And therefore getting an error with Zombies enabled.
How can I update my code in either the view controller or the service, so that when the view controller is removed (popped off the nav controller stack) the service with the delegate pointer also gets removed from memory?
It turns out that it's not me that's doing anything wrong...
The offending NSZombie turned out to be due to the MKMapViewDelegate, which keeps sending 'mapView:didUpdateUserLocation:' after the View Controller it belongs to gets deallocated. I know.
I resolved it by intercepting the Back button in my View Controller, and set the delegate to nil before popping it:
- (void)backButtonTapped
{
self.mapView.delegate = nil;
[self.navigationController popViewControllerAnimated:YES];
}
I don't know why MapKit holds onto a delegate after it has been dealloc'd. If anyone knows I'd be grateful to find out more.