Xamarin Forms navigation not working as expected in debug mode - c#

We are working on a xamarin forms app where INavigationService is used for navigating between pages. I found a strange observation that i haven't come across.
Observation 1: App is deployed in Emulator/simulator and debug mode is stopped.
=> Navigation is working as expected
Observation 2: App is tested while running i debug mode.
=> Navigation to few screens not happening until user clicks randomly on screen. i.e, when user navigates from ClassA to ClassB the control(code execution) is shifted from ClassA to ClassB but UI still shows ClassA and when user clicks on screen randomly it navigates to ClassB UI ,the method in which the Navigation code is written in ClassA doesn’t end until user click on screen.
Code:
Class A VM:
private async Task ContinueToNextPageCommandAsync()
{
IsBusy= true;
if (listofItems <= 0)
{
await DialogService.ShowAlertAsync("Warning");
return;
}
await NavigationService.NavigateToAsync(typeof(ClassBViewModel), parameter);
IsBusy= False;
return;
}
Class B VM:
public override async Task InitializeAsync(object navigationData1,
object navigationData2 = null, object navigationData3 = null)
{
try
{
IsLoadingText = true;
// Statements to be executed during class initiation
IsLoadingText = false;
}
}
Note: IsBusy=False in classA doesn’t gets triggered until user clicks on screen after navigation.

Related

AppDomain.CurrentDomain.SetThreadPrincipal problem

To cut whole thing short, here is the WPF startup and probably where the problem lies.
protected override void OnStartup(StartupEventArgs e)
{
CustomPrincipal customPrincipal = new CustomPrincipal();
AppDomain.CurrentDomain.SetThreadPrincipal(customPrincipal);
//Show main window and inject dependencies
AuthViewModel viewModel = new AuthViewModel(new AuthenticationService());
IMainViews mainWindow = new MainWindow(viewModel);
mainWindow.Show();
}
I set AppDomain.CurrentDomain.SetThreadPrincipal(customPrincipal) where customPrincipal is my own implementation.
The thing is, it works... for main window at least, then through debugger i put some breakpoints on different events, upon observing Thread.CurrentPrincipal on those breakpoints it seems it somehow evaluated the whole thing to null later on. While when the whole MainWindow initalization is in process Thread.CurrentPrincipal is customPrincipal as it should be. After mainWindow.Show() i dont have Principal anymore.
AppDomain should set any thread on app domain to use the principal set on app startup?
Possible things to note is that i use Prism and this is done on .netcore 3 WPF if that makes any difference.
Update 1: IPrincipal implementation
public class CustomPrincipal : IPrincipal
{
private CustomIdentity _identity;
public CustomIdentity Identity
{
get { return _identity ?? new AnonymousIdentity(); }
set { _identity = value; }
}
IIdentity IPrincipal.Identity
{
get { return this.Identity; }
}
public bool IsInRole(string role)
{
return _identity.Role == role;
}
}
AnonymousIdentity() just returns empty strings for all properties including Name which also works just fine for first window.
For now it seems that i misunderstood how exactly AppDomain.CurrentDomain.SetThreadPrincipal works(or that is exactly how it works hmm)
I added a checking for weather a Thread.CurrentPrincipal is null.
In case it is, I instantiate a new CustomIdentity() object with info whether user is indeed signed in or not and then instantiate either AnonymousIdentity() or return the actual user.
It kinda kills the point of AppDomain.CurrentDomain.SetThreadPrincipal but i just could not get it to attach to Thread for a whole domain and switch it upon user input without it ever evaluating to null, which I initially thought is the main purpose of this method.
I believe this not be a real answer but rather a hacky workaround(with this i can actually delete the whole AppDomain setup) so if someone has more experience with this please share your opinion. Thanks

Can a UWP App Self Activate Its Window?

public class MainViewModel MyViewModel : INotifyPropertyChanged
{
Window window { get; set; }
public MyViewModel()
{
window = Window.Current;
}
async void MyWebSocketService_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ActivateWindow"
ActivateWindow();
break;
}
}
void ActivateWindow()
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
window.Activate();
window.CoreWindow.Activate();
});
}
}
I'm trying to get a hidden or minimized UWP app to regain focus in the OS upon a WebSocket notification. This is the code I tried. It fires but nothing happens. Is there a way to achieve what I'm trying to do?
A UWP app cannot resume itself from minimized state because its execution state is suspended (and therefore can't run any code). The resume needs to be triggered externally, either by the user or by another running app, which can activate the suspended UWP app via any of the supported app activation APIs, for example doing a launch via protocol - as you have already figured out.

WebView in background won't load webpages

I want my app to navigate every five minutes to a certain webpage while the display is off. Therefore i created an AlarmReceiver:
[BroadcastReceiver]
public class BackgroundAlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
MainActivity.Current.RunOnUiThread(() =>
{
FMain.WV.LoadUrl("http://127.0.0.1/");
});
}
}
WV is attached to the layout of the fragment 'FMain' and a static parameter of it.
This works fine while the screen is on, but when I turn my screen off and turn it on a few minutes later, most of the times I get to see "Webpage not available, ERR_NAME_NOT_RESOLVED" (but sometimes it loads even while the screen is of).
The webview has DomStorage and JavaScript enabled and a standard WebViewClient:
public class MyWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
{
view.LoadUrl(request.Url.ToString());
return false;
}
}
It happens, because android system kills your web view. Do you really need to render some page every 5 minutes in background, or you just want to send request?

Stopping Background Task On Page Navigation Back

I'm working on a Xamarin.Forms project that supports iOS and Android devices, and I'm using the MVVM design pattern.
I have navigation root page that consists of a ListView, when item is selected on this ListView, I execute the following command to Navigate to item details view.
Page DetailsPage = new View.DetailsView(SelectedItemData);
await Navigation.PushAsync(DetailsPage);
Once this Details Page is opened, I start running a background task.
private void StartBackgroundTask(){
TimerBackgroundTask = new Timer((o) => {
Device.BeginInvokeOnMainThread(() => Update()); }, null, 0, 1000);
}
}
Which is based on this class
public class Timer : CancellationTokenSource
{
public bool IsDisposed { get; set; }
public Timer(Action<object> callback, object state, int dueTime, int period)
{
System.Threading.Tasks.Task.Delay(dueTime, Token).ContinueWith(async (t, s) =>
{
Tuple<Action<object>, object> tuple = (Tuple<Action<object>, object>)s;
while (!IsCancellationRequested)
{
await System.Threading.Tasks.Task.Run(() => tuple.Item1(tuple.Item2));
await System.Threading.Tasks.Task.Delay(period);
}
},
Tuple.Create(callback, state), CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default);
}
protected override void Dispose(bool disposing)
{
IsDisposed = true;
if (disposing)
{
Cancel();
}
base.Dispose(disposing);
}
}
Update function updates UI every 1 second.
Everything works fine and as it should, no issues here, however problems start to occur once I navigate back to root page, and back to details page - doing so twice causes the following error:
System.ArgumentException'jobject' must not be IntPtr.Zero. Parameter name: jobject
The problem stops occurring once the StartBackgroundTask gets disabled entirely from the code, so I believe that it is the one responsible for the error. Furthermore, I'm fairly convinced that this background task keeps on running somewhere in the thread even though I navigate back to the root page and I believe that if I could somehow dispose of the background task OnDissapearing event / navigation back button pressed, the error would no longer persist.
Unfortunately I have no idea how I how or even if its possible to somehow bind command to navigation back pressed event given my Views are bound to ViewModel.
Any tips would be greatly appreciated.
You can detect that a page is being dismissed by overriding OnDisappearing. In your DetailPage you could have something like this:
protected override void OnDisappearing()
{
TimerBackgroundTask?.Dispose();
base.OnDisappearing();
}

MvvmCross and view navigation

I'm using MvvmCross for my application and starting with iPhone. To achieve the sophistication on navigating between views using RequestNavigate and Close I've derived a new presenter from MvxBaseTouchViewPresenter. So far so good.
The problem I'm having now is that it is possible to close or show a view while the previously visible view is still in transition, either opening or closing. The only way I could think of to work round this problem was to use the ViewDidAppear and ViewDidDisappear event handlers of view controllers to call an Action that does the showing of the next view thereby deferring the showing until after the previous view has finished its transition.
This means I have to add:
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
DoPostTransitionAction();
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
DoPostTransitionAction();
}
private void DoPostTransitionAction()
{
if( _postTransitionAction != null)_postTransitionAction();
}
private Action _postTransitionAction;
public void ShowActionAfterTransition( Action postTransitionAction)
{
if( this.IsBeingDismissed || this.IsBeingPresented)
{
_postTransitionAction = postTransitionAction;
}
else
{
_postTransitionAction = null;
postTransitionAction();
}
}
to view controllers, introduce an IEventViewController interface to make me add the code and change the Show method of the presenter to be:
public override void Show(MvxShowViewModelRequest request)
{
// find the current top view as it will disappear as a result of
// showing the requested view
// note: this will be null for the first show request
var topViewController = TopViewController;
// if the request is to roll back an existing stack of views
// then rollback to the bottom of the stack
if (request.ClearTop && topViewController != null)
{
RollBackStack(topViewController);
}
// the top view is about to be 'covered' by the view requested
// if the top view is transitioning (appearing or disappearing)
// then wait for it to finish before showing the view requested
var disappearingViewController = topViewController as IEventViewController;
// if the top view is disappearing and it's of the 'event' type
// delay calling Show until after the view has disappeared
if( disappearingViewController != null)
{
// the top view has been requested to close and will fire the
// 'transition complete' event when it has
// register the action to perform when the top view has disappeared
disappearingViewController.ShowActionAfterTransition (() =>
{
Show (CreateView(request), true);
});
}
else
{
// show the view now as the top view is either not closing
// or, if it is, is not going to say when it does
// create a view controller of the type requested
Show(CreateView(request), true);
}
}
What I'd really like to have would be those event handlers in the base class. I wonder what are the chances without me setting myself adrift from the main development path? Partial classes might do it?

Categories

Resources