Navigate away after PhoneNumberResult - c#

This is specifically a Caliburn.Micro question I think, as it has to do with how CB handles navigation in windows phone 7.
I have a view that has the option of launching a phone number chooser. Once the result comes back I store it and navigate away, only the navigation wont work. I assume this is because the Handle method is working with the task and not my view. I know I can stick a button down the end of the page to navigate after the handle is finished but I would like this to happen once the result comes back.
This is what I am doing.
public void Handle(TaskCompleted<PhoneNumberResult> message)
{
webtext.Recipient = message.Result.PhoneNumber;
webtext.RecipientDisplayName = message.Result.DisplayName;
CommitWebtextToStorage();
events.Unsubscribe(this);
navigationService.UriFor<ComposeViewModel>();
}
Which wont work. I also can't call a method inside that as that would be the same as what I am doing. I need to let the handle method exit and then call the navigation service.

Actually, the navigation should look like:
navigationService.UriFor<ComposeViewModel>().Navigate();
(note the final Navigate method)
If it was just a typo in the question, I guess the issue could have to do with the timing of application resuming (which occurs when you return back to the application after the chooser task is completed).
In that case, could you please create an issue for this?

Related

c# - How to set all the application as the owner of Form.showDialog()

I have a Windows Desktop App with an auto-update method implemented. I want to show a custom Form (because I need to change the button texts) asking the user if he or she wants to download the new version or not when a new update is detected and I want to "block" all input actions in the Desktop App until the user has made his selection.
After reading Form.ShowDialog() documentation and several topics here saying "ShowDialog() is not making my windows modal" and several answers replying "You need to properly set the owner" I still don't understand how to set this owner. Of course if I make two forms and the first one shows the second, I can "block" the first one doing:
secondForm.ShowDialog(firstForm);
But I don't know how to make that the firstForm blocks all the application to prevent the user using a deprecated version of it.
I tried several approaches like getting the current id process (or trying to get it) and convert it to IWin32Window. But nothing seemed to work.
If you need it, I add here the code I'm using:
FormAsk formAsk = new FormAsk (param1, param2);
formAsk.StartPosition = FormStartPosition.CenterParent;
formAsk.TopLevel = true;
formAsk.TopMost = true;
formAsk.DialogResult = formAsk .ShowDialog();
if(formAsk.DialogResult.Equals(DialogResult.OK))
{
// do stuff
}
else
{
// do other stuff
}
I've also seen lots of solution implementing:
myForm.ShowDialog(this);
But VS start's crying because the types are not compatible. I'm using a MVVM pattern so I can't just set a Form as an owner because I don't have a main form. Just views in .xaml and views controllers in c#.
Edit: I would like to add few comments I learned after facing this issue that may help to understand better my situation.
The main method of the program executes the following:
[STAThread]
static void Main()
{
//stuff
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
//stuff
STAApplicationContext context = new STAApplicationContext();
Application.Run(context);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, Localization.Strings.error_popup_title);
Application.Exit();
}
}
}
And this context is the one that generates the service layer and views manager of the application. If I display the Forms in the service layer, showDialog() method can not "block" the input in the views but if I display them from the views (generated and handled by the view manager) i can. There's a communication between views and service, because actions triggered in the views have as consequence a service method call, but in this case the communication I want is the opposite: the service calling the methods in the view controllers to display the Forms by showDialog().
You need to pass an instance of the IWin32Window interface to the ShowDialog method.
IntPtr myWindowHandle = IntPtr(parent.Handle);
IWin32Window w = Control.FromHandle(myWindowHandle);
Do your Stuff in your first Form and whatever button you press to create your second Form just go like this. (Pseudo Code)
button1_click()
{
Form2 = new Form()
Form2.Owner = this;
}
and now from your Form2 you can talk to your Owner with this.Owner.Visible = false for example.
Thats how you make the Owner if thats what you asked for.
Thanks those who tried to help with your replies. However, although your answers probably will work in other circumstances, mine where a bit different.
Finally I achieved to solve it, I needed to do the handle with Forms in a higher level of abstraction. The information managed was retrieved from an asynchronous task so I couldn't use there a showDialog method and block the MainWindow of the application. Instead I did several threads, wait them and eventually show dialogs when I needed. It's not the best approach, but given the context is the only thing I could do.

MVC background process preventing navigation to other pages while running

I have an app that launches a long update on the backend (Dynamics 365 in this case). I want to launch it in the background while the user can continue doing things.
The problem is that while this task is running, the other pages don't load when I click on them. Maybe is the usual behavior.
Tried with Task.Run() HostingEnvironment.QueueBackgroundWorkItem() and the result is the same.
This is how my controller looks like:
public ActionResult ConfirmCurrentMonthMeetings() {
//Task.Factory.StartNew(() => QueryHelper.MarkReadOnlyCurrentMonthMeetings(guide.Id, svc));
HostingEnvironment.QueueBackgroundWorkItem(clt => QueryHelper.MarkReadOnlyCurrentMonthMeetings(guide.Id, svc));
ViewBag.ConfirmingMeetingsMessage = "Meetings being confirmed on the background. This action might take a few minutes";
PrepareMainScreen();
return View("MainScreen");
}
Apparently the variable svc that I use to perform the queries to the CRM is a shared resource and cannot be used while it's in use. I defined a second one and worked fine.

MvvmCross show view before going further

I have an application where I can use popup views over the normal windows.
For getting the data the user needs to login so I have a token.
Has anyone experience with the way if there is no token, show first a view, then go further where you was heading to?
To make it more clear:
public void Init()
{
if (!CheckToken())
{
Task.Run(() => ShowViewModel<InsertPasswordViewModel>())
.ContinueWith(t => GetData());
}
else
{
//Do your thing
GetData();
}
}
The problem now is that the task is run so view is shown and immediately starts GetData but he has no token and crashes.
Any ideas or fixes are welcome
You shouldn't do navigation in Init. You are essentially navigating away from a page you are in the middle of navigating to. The navigation isn't finished executing when Init is called.
You are not getting a result from ShowViewModel either, so you can't rely on that returning anything when you are done with everything in InsertPasswordViewModel.
What you are probably looking for is navigating to your ViewModel with some kind of parameter telling where you came from. Then let InsertPasswordViewModel use that parameter to navigate back once password is OK.
You probably want to modify the View hierarchy too, which you can do through a custom presenter and a set of presentation hints.

Cannot resolve current top activity while showing viewmodel using mvvmcross

I'm implementing a custom presenter in my Mvvmcross application. What I wanted to accomplish is: regular navigation and fragment navigation.
In my main activity, I managed to embed several fragment views based on this example: https://github.com/i486dx400/MultiRegionPresenter
while the fragments are working, I also wanted to show regular activities, that aren't hosted as a fragment. Therefor I extended this presenter as shown in this snippet: https://gist.github.com/JelleDamen/7003702
The problem/bug:
When I show this second activity, it gets shown. But when I go back to the previous view (which is the host) and re-open the same activity again, it doesn't get shown. The output log says: "mvx:Warning: Cannot Resolve current top activity"
What am I doing wrong, or what should I do, to inform the framework what activity is the current top activity?
Thanks in advance!
What is going wrong?
The line of trace you have provided is shown from:
protected virtual void Show(Intent intent)
{
var activity = Activity;
if (activity == null)
{
MvxTrace.Warning("Cannot Resolve current top activity");
return;
}
activity.StartActivity(intent);
}
in https://github.com/MvvmCross/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Droid/Views/MvxAndroidViewPresenter.cs
So it would appear that when Show is called, then there is no current MvvmCross Activity shown.
... and looking at https://github.com/i486dx400/MultiRegionPresenter/blob/master/RegionEx.Droid/MainActivity.cs it does appear this is true - the main activity in the app is not adapted for MvvmCross, but is instead just a normal FragmentActivity.
what should an app do to inform the framework what activity is the current top activity?
MvvmCross normally tracks the "top activity" by intercepting Activity lifecycle events - specifically the Activity created, started, restarted, resumed and destroyed events. These are shown in the lifecycle diagram in http://developer.android.com/reference/android/app/Activity.html
MvvmCross:
hooks into these events via the MvxActivityAdapter in https://github.com/MvvmCross/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Droid/Views/MvxActivityAdapter.cs
these hooks call the extension methods in https://github.com/MvvmCross/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Droid/Views/MvxActivityViewExtensions.cs
these extension methods inform the lifecycle monitor about the lifecycle changes - see https://github.com/MvvmCross/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Droid/Views/MvxAndroidLifeTimeMonitor.cs#L35 -
All the built-in MvvmCross Activity types - MvxActivity, MvxFragmentActivity, etc - call these "automatically". These adaptions can be extended to other Activity types using steps like those described in ActionBarSherlock with latest MVVMCross, or your app can manually call some of these hooks if it prefers.
Personal opinion: I think you'd be better off not following https://github.com/i486dx400/MultiRegionPresenter too closely. The code in OnCreate in https://github.com/i486dx400/MultiRegionPresenter/blob/master/RegionEx.Droid/MainActivity.cs seems to try to Start the app every time that MainActivity is created - which can, of course, happen multiple times during the lifecycle of each app.
Instead, read that sample and others like http://motzcod.es/post/60427389481/effective-navigation-in-xamarin-android-part-1, https://github.com/jamesmontemagno/Xam.NavDrawer/tree/master/Mvx and http://enginecore.blogspot.ro/2013/06/more-dynamic-android-fragments-with.html - then implement something that suits your navigation needs.

"Navigation is not allowed when the task is not in the foreground" in WP7 application

I m getting an error in WP 7.1 like below
InvalidOperationException
"Navigation is not allowed when the task is not in the foreground"
In the following line of code
NavigationService.Navigate(new Uri("/PhotoPreview.xaml", UriKind.Relative));
I dont have any clue how to solve it. It would be great if you can provide some pointers
If you need to call it from the main UI thread, use this:
Dispatcher.BeginInvoke(() =>
{
NavigationService.Navigate(new Uri("/PhotoPreview.xaml", UriKind.Relative));
});
While using Dispatcher.BeginInvoke may help, it may well not fix your issue. I've also seen this occur if there is a race condition between 2 conflicting navigations, e.g. back key and forward navigation, or 2 forward navigations. See discussion on App Hub.
I'm reading between the lines here and assuming that you are using either the CameraCaptureTask or PhotoChooserTask due to the navigation string you are using "/PhotoPreview.xaml".
After battling with this issue myself I found that not only do you need to ensure that the navigation is called on the UI thread ( by using Dispatcher.BeginInvoke() ) but the CameraCaptureTask object must be declared with class scope within the PhoneApplicationPage class and you must call the chooser constructor and assign the Completed event delegate within the page’s constructor.
private readonly CameraCaptureTask cameraCaptureTask;
public MainPage()
{
cameraCaptureTask = new CameraCaptureTask();
cameraCaptureTask.Completed += CameraCaptureCompleted;
}
otherwise your application will be deactivated in the background and will never recieve the photo. Causing the application to crash with one of the following exceptions:
Navigation is not allowed when the task is not in the foreground
0x8000ffff
Navigation is not allowed after the task has been
canceled. Error: -2147220992
Navigation is not allowed when the task
is not in the foreground. Error: -2147220990
Some further tips:
Don't remove the event handler in your CameraCaptureCompleted method either or it won't work the next time around!
You may also want to add some code to ensure that navigation can't occur twice due to multiple button clicks for example; the touch screens can be quite sensitive! If you are only using the capture task, a try catch block around the Show() call to trap an InvalidOperationException should be fine.
tl;dr
Only assign the CameraCaptureTask/PhotoChooser and it's event handler in your page constructor.

Categories

Resources