I am currently trying to add additional functionality onto an existing application, and have started using MvvmCross for the new screens, therefore I have a hybrid app on my hand right now. I want to navigate from an old screen to a new screen using ViewModel, and passing an object in memory as well. I've followed the suggestions from here:
Using Notifications on android with MvvmCross
Here is my code:
var viewModelRequest = MvxViewModelRequest<MyViewModel>.GetDefaultRequest ( );
viewModelRequest.ParameterValues = new Dictionary<string, string> ( );
viewModelRequest.ParameterValues.Add ( "myobject", JsonConvert.SerializeObject ( this.myObject, Formatting.None ) );
var intent = Mvx.Resolve<IMvxAndroidViewModelRequestTranslator>().GetIntentFor ( viewModelRequest );
this.StartActivity ( intent );
When I run this code, it throws a null object exception at the point where it tries to solve the IMvxAndroidViewModelRequestTranslator. I took a quick look at the mvvmcross code, and notice that the InitializeSecondary() (where InitializeViewsContainer() is called) is only called in the InitialieFromSplashScreen() method. My question is, is it because my splash screen did not inherit from MvxSplashScrennActivity, that my viewcontainers are not initialized properly? If that is the case, can I do this intialization somewhere manually?
There are a number of methods you can use to attempt to initialize things when your app runs from within the Setup class. Reference the initial response from here where it discusses calling
protected override void InitializeLastChance(){};
Platform-specific IoC in MVVMCross
IMHO, it may be easier to just inherit or work with the built in splash class to ensure you don't run into more gotchas down the road however.
Related
I'm working on a UWP app that hosts a WebView which runs in a separate process.
var webView = new Windows.UI.Xaml.Controls.WebView(WebViewExecutionMode.SeparateProcess)
This results in a behavior that if the WebView has the focus, the containing app can't regain the focus by itself by simply trying to focus on a UI element.
The app supports keyboard shortcuts which may result in different elements getting the focus, but it's not working correctly when the focus is captured by the WebView. The target element seems to be getting the focus but it seems as if the process itself is not activated (as the real focus resides in a different process I suppose...).
I'm currently trying to activate the app programmatically through protocol registration in an attempt to regain focus.
I added a declaration in the app manifest for a custom protocol mycustomprotocol coupled with the following activation overload
protected override void OnActivated(IActivatedEventArgs args)
{
if (eventArgs.Uri.Scheme == "mycustomprotocol")
{ }
}
And the following code to invoke the activation:
var result = await Windows.System.Launcher.LaunchUriAsync(new Uri("mycustomprotocol:"));
Seems to be working only on some computers, on others (not while debugging the app, only when executed unattached) instead of regaining focus the app's taskbar icon just flashes orange.
I've created a sample project showing the problem and the semi working solution here
Any insight on any of this would be great.
I can reproduce your issue. I found that when we switch the focus with the mouse, the focus can be transferred to the TextBlock. So you could solve this question through simulating mouse input.
Please use the following code to instead FocusTarget.Focus(FocusState.Programmatic).
As follows:
InputInjector inputInjector = InputInjector.TryCreate();
var infoDown = new InjectedInputMouseInfo();
// adjust your mouse position to the textbox through changing infoDown.DeltaX,infoDown.DeltaY
infoDown.DeltaX = 10; //change
infoDown.DeltaY = -150; //change
infoDown.MouseOptions = InjectedInputMouseOptions.LeftDown;
var infoUp = new InjectedInputMouseInfo();
infoUp.DeltaX = 0;
infoUp.DeltaY = 0;
infoUp.MouseOptions = InjectedInputMouseOptions.LeftUp;
inputInjector.InjectMouseInput(new[] { infoDown, infoUp });
Note: If you use the input injection APIs, you need to add inputInjectionBrokered Capabilitiy in your Package.appxmanifest.
But this Capabilitiy is a restricted Capabilitiy, you can’t publish this app in store, which can’t pass the verification.
I've been in discussions with a WebView software engineer. The problem is that the separate process still wants to own focus if you try to move the focus away from the webview. His solution is to ask the other process' web engine to give up focus with the following call:
_= webView.InvokeScriptAsync("eval", new string[] { "window.departFocus('up', { originLeft: 0, originTop: 0, originWidth: 0, originHeight: 0 });" });
You can call it before trying to change the focus to your target. I ran various tests and it works consistently.
I'm developing an application for W10 Mobile (UWP) in Xamarin forms and I have implemented a WebView and I tried to get the URL of this but it is more complicated than I thought at first, I tried to get it through the source property, but not is possible, I would appreciate a help.
You could create an event handler to the navigation completed event.
With that you can check the URL
example:
WebView browser = new WebView();
browser.Navigated += OnNavigatedHandler;
public void OnNavigatedHandler (object sender, WebNavigatedEventArgs args){
Console.WriteLine ("Navigated to: " + args.Url);
}
I'm having trouble getting the URL of the browser in real time, the way you indicate I enter an infinite loop, I have a binding in my WebView on the SourceProperty in the view model called URL, when there is a change in the URL property I detect it thanks to PropertyChanged, the problem is that the event navigated only runs when updating the value of the URL property which causes the infinite loop to load the WebView infinitely. Is there any other way to get the URL?
I have uploaded in Pastebin the classes of the test project I am using:
View: pastebin.com/msyu9dJF
ViewModel: pastebin.com/LaCfC31c
BaseViewModel: pastebin.com/i6GCFbbe
I'm trying to get route-me to show an offline map which is bundled or to be downloaded after app installation. I'm using route-me bindings sample project to get the work done just for now. I also use the mbtiles file from the original route-me repo's SampleMap project. I copy the file to project's root directory and set it's build action to BundleResource (that's what I thought would be appropriate). After that I changed to code to this :
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
RMDBMapSource dbSource = new RMDBMapSource ("Philadelphia.mbtiles");
MapView = new RMMapView(View.Frame, dbSource.Handle);
MapView.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
if (UIScreen.MainScreen.Scale > 1.0)
MapView.AdjustTilesForRetinaDisplay = true;
Add (MapView);
}
But no luck. App runs in the simulator but showing only a grey background nothing more. So I need someone to help me and tell me what I'm doing wrong. I need to get it done this week since next week is the deadline for project. So any help would be appreciated.
I haven't actually used offline tiles myself, but based on this thread it looks like you might need to put the RMDBMapSource into an instance of RMMapContents instead of directly into the MapView. So I'm thinking it would be something like this with Xamarin:
RMDBMapSource dbSource = new RMDBMapSource ("Philadelphia.mbtiles");
MapView = new RMMapView(View.Frame, new IntPtr());
RMMapContents contents = new RMMapContents (MapView.Handle, dbSource.Handle);
That assumes you have a wrapper binding for RMMapContents too which from the looks of it the bindings project does not have by default. You'd need to throw in a wrapper that at least defines the constructor.
This page looks like it provides similar code (in Obj-C) towards the bottom.
I have started developing html applications for mutliple platforms. I recently heard about Cordova 2.0(PhoneGap) and ever since I have been curious to know how the bridge works.
After lot of code walking, i saw that the Exec.js is the code where call from JS -> Native happens
execXhr = execXhr || new XMLHttpRequest();
// Changeing this to a GET will make the XHR reach the URIProtocol on 4.2.
// For some reason it still doesn't work though...
execXhr.open('HEAD', "file:///!gap_exec", true);
execXhr.setRequestHeader('vc', cordova.iOSVCAddr);
if (shouldBundleCommandJson()) {
execXhr.setRequestHeader('cmds', nativecomm());
}
execXhr.send(null);
} else {
execIframe = execIframe || createExecIframe();
execIframe.src = "gap://ready";
But want to understand how that works, what is the concept here, what does file:///!gap_exec or gap://ready do? and how does the call propgate to the lower layers (native code layers)
thanks a bunch in advance.
The trick is easy:
There is a webview. This displays your app. The webview will handle all navigation events.
If the browser navigates to:
file:///!gap_exec
or
gap://
the webview will cancel the navigation. Everything behind these strings is re-used as an identifier, to get the concrete plugin/plugin-method and parameter:
pseudo-url example:
gap://echoplugin/echothistext?Hello World
This will cause phonegap to look for an echoplugin and call the echothistext method to send the text "Hello World" to the (native) plugin.
update
The way back from native to javascript is (or may be) loading a javascript: url into the webview.
The concrete implementation is a little bit more complex, because the javascript has to send a callback-id to native code. There could be more than one native call are running at the same time. But in fact this is no magic at all. Just a number to get the correct JSON to the right javascript-callback.
There are different ways to communicate between the platform and javascript. For Android there are three or four different bridges.
I am trying to figure this out in more detail, too. Basically there are 2 Methods on the iOS side that can help ...
- webView:shouldStartLoadWithRequest:navigationType: and
- stringByEvaluatingJavaScriptFromString:script
From the sources it seems cordova sends a "READY" message using webView:shouldStartLoadWithRequest:... and then picks up results with the second message, but I am not sure.
Cordova Sources iOSExec
There is much to learn there.
I have a BlackBerry UiApplication, which registers some menu items in the standard Phone and Contacts applications. I need the menu items to be registered on phone startup, ie, before my UiApplication is started.
I can achieve this if I configure my UiApplication to auto-run on startup, and register the menu items in my app initialisation code using ApplicationMenuItemRepository.
My problem is that every time my UiApplication is subsequently opened, my initialisation code is run again, and I get duplicate menu items in the Phone and Contacts app. ApplicationMenuItemRepository does not provide an API to check if they are already registered. Using a static boolean in my own code also does not help, presumably because different classloaders are used for each app instance.
Am I using the wrong approach here? Should I have a separate Application (to register Phone/Contacts menu items) and UiApplication (for my views)? That feels overly complex for my needs.
Use the Alternate Entry Point
Click on the project node.
Right click and select Properties.
In the Properties window, select the Application tab.
Ensure the following options are checked: Auto-run on startup and System module (to register the thread with the system).
Create another project under the same folder as the original project. Right click on the new project node and select Properties.
Select the Application tab and select Alternate CLDC Application Entry Point from the Project type drop down menu. As shown in the attached file, select the name of the original project (for example: trafficreporter) from the Alternate entry point for drop down menu. Also specify the arguments that would launch the application using this alternate entry point (for example: gui).
Modify the main() method of the original project as follows:
public static void main(String[] args) {
if ( args != null && args.length > 0 && args[0].equals("gui") ){
// code to initialize the app
theApp.enterEventDispatcher();
} else {
// code to launch the background thread }
}
}
Add your application iconfile to the this new "Entry Point" application and make it the ribbon icon.
Use the removeMenuItem() method when the user exits your application. it will work.
if(_serverMenuItem != null) {
ApplicationMenuItemRepository.getInstance().
removeMenuItem(ApplicationMenuItemRepository.MENUITEM_PHONE,_serverMenuItem);
}
If you want to add custom menu fields to native applications you can use a RunTime store to register you menu item and then check for it while you re-run your code :
ApplicationMenuItem ami = new ApplicationMenuItem(placement); // some placement you want to use e.g 0x35090
ApplicationMenuItemRepository amir = ApplicationMenuItemRepository.getInstance();
RuntimeStore store = RuntimeStore.getRuntimeStore(); // get the store instance
if(store.get(ApplicationMenuItemRepository.MENUITEM_CALENDAR) == null)// if object is not added only then add the item to the menu
{
try
{
store.put( ApplicationMenuItemRepository.MENUITEM_CALENDAR, ami );
}
catch(IllegalArgumentException e){}
amir.addMenuItem(ApplicationMenuItemRepository.MENUITEM_CALENDAR, ami);
}