Xamarin.iOS AutoLayouts (Cirrious.FluentLayout) and PresentViewController weird behvaior - c#

I am seeing constraints errors in my output window when I invoke a UIViewController using PresentViewController
Here is what my view heirarchy looks like:
MainViewController (RootViewController)
Outer MainVC Button
Nested UINavigationController (Nav1)
FirstViewController (Nav1.RootViewController)
Nested FirstVC Button
MyModalViewController (Presented by invoking PresentViewController)
dismiss button
Everything works as expected when MyModalViewController is shown from the Outer MainVC Button, but when I do the same from the Nested FirstVCButton and dismiss it to return back, I get constraint errors and the Nav1 is gone from the MainViewController
I just want to understand why this is happening and any potential workarounds are also welcome.
Full Source Code replicating this issue can be found here
https://github.com/raghurana/XamarinIosAutoLayoutBug
Edit
It's a requirement to present MyModalViewController (well modally, thus PresentViewController instead of Push Or Show) due to UX design requirements.

Related

What is the best approach to create a Visual Studio-like Start Window using ReactiveUI?

I want to make a Start / Welcome / Solution selection window which has similar functionalities to the one used in VS19 / VS22, but I'm not sure how to do it exactly.
For more context, my current StartWindowView has a "Create New Project..." button, which should replace the entire window content with a 2-page project creation wizard.
Page 1 should be "Basic Options" where on the bottom there are "Cancel" and "Next" buttons ("Cancel" goes back to the original StartView and "Next" goes to Page2View).
Page 2 should be "Extra Options" where on the bottom there are "Back" and "Finish" buttons ("Back" goes back to Page1View and "Finish" goes back to the StartView, returning a ProjectModel)
From my understanding, these are the ViewModels I'd have to deal with:
StartWindowViewModel // Main window host (possible router)
StartViewModel // Main project selection view
ProjectCreationViewModel // Possible router for Page1 & Page2
ProjectCreationPage1ViewModel // Basic options
ProjectCreationPage2ViewModel // Extra options
My idea was to use Routing, but I don't know if that's the right approach, since I'm not sure if the data between Page1 and Page2 will be preserved when going back and forth.
Also, the routing examples I saw for ReactiveUI have fixed "Back" and "Next" buttons on the bottom, therefore it makes me think that this might not be the solution for my problem, since pressing the "Create New Project..." button replaces the StartViewModel with the ProjectCreationViewModel, making manual navigation impossible.
I might be completely wrong though. I'm really unsure on how to approach this problem.
EDIT: This is how the VS22 start window looks like:
and this is what happens when you press the button marked in red:
As you can see, the entire window changes the current View.
It's not terribly difficult, just keep an observable collection of your view model stack, and always display the last one (or the first one, it's easier with WPF bindings). Note that I'll be referring to this as a stack, but there is no ObservableStack<> already built for you. Either use an ObservableCollection<> or build your own observable stack.
Then as you need to navigate "into" your wizard (new project, clone a repository, etc), you simply push the new child view model onto the stack. When you need to navigate "out of" your wizard (ie, on Cancel), pop the last view model from the stack.
The last step is to associate your views to view models (using DataTemplate in a high-level resource block, either a global one or a local one in your start page) and then bind your view model stack's top to your main window (the shell that has a ContentControl bound to the top of your stack).

iOS View Controllers not being released?

(I'm using c#/Xamarin, but doubt the issue is specific to that.)
When I add a View Controller and then remove it - it's DidReceiveMemoryWarning is still called (in the Simulator and on real devices), so it can't have been released. I've narrowed it down to this:-
UIViewController vc=(UIViewController)this.Storyboard.InstantiateViewController(identifier);
this.AddChildViewController(vc);
vc.RemoveFromParentViewController();
vc=null;
and calling DidMoveToParentViewController and WillMoveToParentViewController (as described in the docs) doesn't help either:
UIViewController vc=(UIViewController)this.Storyboard.InstantiateViewController(identifier);
this.AddChildViewController(vc);
vc.DidMoveToParentViewController(this);
vc.WillMoveToParentViewController(null);
vc.RemoveFromParentViewController();
vc=null;
then simulate a memory warning and vc DidReceiveMemoryWarning gets called even though there is no reference to it. How is this possible when it's been removed as child controller and there is no reference to it.
(The same is happening when I use a segue set up in a Storyboard to go to a detail view in a UINavigationController, for example, after going "back" to the root controller, the detail controller still gets DidReceiveMemoryWarning messages.
Any help to understand this would be appreciated
UPDATE:
Now the problem I have is with a simple UIViewController embedded in a UINavigationController
I add the navigation controller:
this.nc=(UINavigationController)this.Storyboard.InstantiateViewController("NavigationController");
this.AddChildViewController(this.nc);
this.nc.DidMoveToParentViewController(this);
and remove later (after it's loaded):
this.nc.WillMoveToParentViewController(null);
this.nc.RemoveFromParentViewController();
this.nc=null;
and this all works fine (it's not retained). BUT if I add this simple line in the ViewDidLoad method of the ViewController thats embedded, then the ViewController IS retained!
Console.WriteLine("this.NavigationController={0}",this.NavigationController);
ie, just accessing "this.NavigationController" causes the VC to be retained!
So each time I run it, I get another ViewController retained!
Any ideas?
It could be that your view controller’s initialization method has some side effect causing it to stay alive. A common example would be that it creates an NSTimer object, which retains its target. Go through the methods that are called when the view controller is instantiated from the storyboard and see if anything retains it.

caliburn micro send data to the dialog

and sorry for the noobness, i'm fairly new to the framework, but i'm beginning to understand it and it's inner workings.
simply put what i want is this:
the shellview recieves an event, from something that happened on a view, logs the problem and shows a dialog informing the user that something wrong happened.
for the creation of the dialog i used this thread and it works without any problems, but i'm lost on how to set the property Message on the view/ViewModel.
help would be appreciated
thanks in advance
I would use the WindowManager directly. Alternatively, you could adapt the code to create a ShowDialog constructor which takes an existing instance of your dialog view model.
In fact that code is a bit messy, ShowDialog should really be generic and take the type of the dialog view model, so that a cast isn't required in order to get the dialog result.

MonoTouch ResignFirstResponder without knowing which UIView is it

I'm building a MonoTouch iPhone app, but have come up with a small issue.
I have a view with 2 UITextFields for login (username/password), however when I first tap on a field, it pops up the keyboard, and the keyboard never disappears again.
The problem is the keyboard hides my "Login" button, so the user cannot tap it.
I'd like the keyboard to resign if I tap anywhere on the "background" of my view.
So I figured out I can do that in TouchesEnded on my UIViewController - however to resign the keyboard I need a reference to the current UIView being FirstResponder.
Which finally leads to my question: Can I find out which UIView is currently FirstResponder without looping recursively through all views from my UIViewController ?
You can use
this.View.EndEditing(true);

WPF and Prism View Overlay

I need some help with overlaying views using the prism framework.Its a little more complexed than that so let me explain.I could be over-thinking this as well :D
i have shell (wpf window) and i have 2 views(A & B - both usercontrols) in a module.
when the shell loads it loads view A. On view A i have a button to "popup" view B
for some user input. so naturally i would think to some sort of modal window/control, maybe even a popup. however the problem i face with the popup is that when i move the shell the popup remains fixed and it doesnt block events in view A. I've tried disabling view A to stop events being fired and i've also tried to use a to get the view B move with the shell. Only the canvas works but i now need a way to block it tho'. Is there anyway i can overlay a view on top of another view with prism? or how does everyone else create modal popups with prism & wpf? any advise or pointers would be greatly appreciated.
If you want to use embedded dialogs without an extra window, you can use Prism's RegionManager to achieve the outlined behavior. The trick is to put the PopUp region parallel to your main region in the visual tree:
<Grid>
<ContentControl cal:RegionManager.RegionName="MainRegion" IsEnabled={Binding IsNoPopUpActive} />
<ContentControl cal:RegionManager.RegionName="PopUpRegion"/>
</Grid>
Now use the RegionManager to put view "A" into the "MainRegion". Create a controller class similar to IPopUpDialogController. It should be responsible for putting your view "B" (or any other PopUpView in your application) into the "PopUpRegion" on demand. Addtionally, it should control a flag that signal the underlying "MainRegion" to be enabled or disabled. This way a user won't be able to play with the controls in your view "A" until the pop up is closed.
This can even be done in a modal fashion by using ComponentDispatcher.PushModal() before pushing a frame onto the Dispatcher. However, I would recommend avoid modal dialogs.
Update: As requested in a comment, the IsNoPopUpActive could be implemented in the backing view model. There you could link it to RegionManager's View collection for the popup region:
public bool IsNoPopUpActive
{
get { return _regionManager.Regions["PopUpRegion"].Views.Count() == 0; }
}
Remember to trigger a PropertyChanged event as soon as you modify the views collection (add/remove a popup).
Just for your information: nowadays I avoid disabling the controls in the background and instead insert a transparent panel. This avoids clicking on background controls. However, this does not handle keyboard input (tab-ing to controls). To fix the keyboard input you need to make sure that the keyboard focus is trapped in the popup (MSDN on WPF Focus concepts).
Adding the following focus attributes to the popup region should do the trick:
KeyboardNavigation.DirectionalNavigation="None"
KeyboardNavigation.ControlTabNavigation="None"
KeyboardNavigation.TabNavigation="Cycle"
KeyboardNavigation.TabIndex="-1"
If you are using WPF + MVVM with Prism you can take a look at this Message View overlay controller. The nice part about this approach is you can write unit tests on you view model using a mock overlay controller and have the mock controller return the result that the user would choose in the overlay.
You can find it here: http://presentationlayer.wordpress.com/2011/05/24/wpf-overlay-message-view-controller/
Hope this helps

Categories