I m having a hard time with this issue.
My MainWindow.xib, has a NavigationController, the view for which is inherited from another xib.
Now, i push a DialogViewController from the main view, but i cannot see a back button on the second view's navigation bar.
Is there anything specific that i need to set for the DialogViewController when it is being pushed from a UIViewController.
Thanks and Regards
Abhishek
The constructor for DialogViewController has a parameter called pushing which you should set to true:
new DialogViewController(rootElement, true); // true will show the back button
Without seeing your code, I'm not sure exactly what's going wrong here. However, from what I know of UINavigationController, the view controller stack starts empty. When you push the first view controller, it gives the navigation controller a view to display, but it has nothing to go 'back' to, so it does not display a back button. If you push a second view, you may get a back button.
Also, be sure that the Title property is set on your child view controllers if you want the back button to reflect the view you will be going back to.
I have a tab bar controller which then hands off to a nav controller (in a storyboard with flyoutnavcontollers too). One of the viewcontrollers from here launches into a dialogviewcontroller for MT.D stuff.
I wanted a lovely pointed/tapered back button from monotouch dialog back to my calling point in the navigation controller.
But launching into MT.D loses the navigation even when im using the current navigation controller for some reason i.e. the button is not displayed and no way to get back. Subsequent mt.d screens give a back button.
Apparently your supposed to pass a true boolean into call to enable back button whilst pushing onto existing stack but this didnt work for me:
this.NavigationController.PushViewController (dv, true);
Dan's above solution didnt work for me. But popping the current dialogviewcontroller whilst at the root MT.D screen helps to get back to my previous position in the original nav controller in the storyboard (or flyoutnav controller).
Not sure if this hack is the correct way but it works.
dv.NavigationItem.RightBarButtonItem = new UIBarButtonItem("Back",UIBarButtonItemStyle.Bordered,delegate(object sender,EventArgs e)
{
NavigationController.PopViewControllerAnimated(true);
});
* update
I manged to get a back button by adding the dialogviewcontroller to current viewcontrollers subview:
dvc = new MyDvcController(this.NavigationController);
this.View.AddSubview(dvc.TableView);
the corresponding MyDvcController mainly loooks like this:
public partial class MyDvcController : DialogViewController
{
public MyDvcController (UINavigationController nav): base (UITableViewStyle.Grouped, null)
{
navigation = nav;
Root = new RootElement ("Demos"){
new Section ("Element API"){
new StringElement ("iPhone Settings Sample", DemoElementApi),
}
};
}
}
this allowed the monotouch.dialog to be part of the current navigation controllers stack and achieve automatic back button with the tapered look ..yay
You can also implement by yourself
dialogViewController.NavigationItem.RightBarButtonItem = new UIBarButtonItem("Back",UIBarButtonItemStyle.Bordered,delegate(object sender,EventArgs e)
{
NavigationController.DismissModalViewControllerAnimated(true);
});
Related
In the first page I have a navigation view and have enabled page cache on this page. Without pushing any other page on this, I can switch between tabs. But once I navigate to a new page and then pop back the navigation stops working. If I disable the cache all of the state is lost which I dont want. Tried setting it to required too. The pages are not heavy I tested by creating a sample app with just a textblock.
<Page
...
NavigationCacheMode="Required">
# Navigation View goes here
</Page>
In the page pushed on top of the main navigation page, I have below code to dismiss the page.
private void OnCloseClick(object sender, RoutedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack) { rootFrame.GoBack(); }
}
Once gone back the navigation simply does not work, what am I doing wrong here ?
Stumbled across the same problem and looks like there's a bug in NavigationView class. Long story short, it is not able to properly recover after Load-Unload-Load cycle (e.g. when it is removed from and added back to view hierarchy - which happens when you navigate from page and back) and stops working.
Update: Checked with NavigationView from WindowsUI SDK. Works like a charm, only settings item seems to be broken yet it still has a problem with selecting items with SelectsOnInvoked set to false (aka conditional select).
How to return to the previous page, and keep previous page content?
I have found this, but there they use a ugly default navigation bar by Microsoft therefore I want to build my own designed nav bar.
How can I do that? I mean I want to navigate from page1 to page2 but when I go back from page2 to page1 I want to return to the same page1 and not to a new instance of it.
Now I'm using this (bad) method:
void PreviousButton(object sender , RoutedEventArgs e)
{
Page2 p2 = new Page2();
NavigationService.Navigate(p2);
}
If you don't want the ui of a frame then don't use pages and don't use a frame as a host.
I've never seen a commercial team use pages in wpf.
Instead, use a contentcontrol to host your stuff.
Usercontrols instead of Pages.
When you instantiate a new UserControl you can add it to a List and retain a reference to the instance. Keep a current index. Navigation "back" would use the previous indexed view, forwards the next.
Usually this would be viewmodels rather than any UI object at all and you'd datatemplate each viewmodel into a view ( with the viewmodel as datacontext ). Retaining a reference to the viewmodel as above.
This viewmodel first navigation is fairly common for child views.
Almost all commercial teams use MVVM.
I have a question that I believe is a little bit weird due to the lack of information I'm finding online.
In my program, there is a UIPageViewController that is overlayed by a UIPageControl. In my UIPageViewController, each View Controller has a table inside with a number of items. With pages being the name for my UIPageControl, when I use pages.UserInteractionEnabled = false; my tap gesture taps underneath of the UIPageControl and taps one of the items in the table, pushing a new view controller for that item. I don't want that to happen, but I also don't want the typical functionality of UIPageControl, which is to scroll left or right depending on the location of the touch. I want this UIPageControl on my user interface for purely the indication of how many pages and which page is the current page.
I've tried removing any existing gesture recognizers from the pages.GestureRecognizers collection and that didn't work. I've tried setting pages.AllTouchEvents += (sender, e) => { return; } which also did nothing.
A thought: I have the UIPageControl as a view that spans the width of the view. Could I add a UIView and then add the UIPageControl as a subview of that, and then call its .SizeToFit() method?
In any case, thanks for taking a look. Any help and/or ideas are appreciated.
Please try pageControl.DefersCurrentPageDisplay = true; to achieve your effect.
When it is set True, the current page indicator will not be rendered until we set the pageControl's CurrentPage to change its selected indicator.
For those who are very familiar with C# or VB.NET using the UserControl component in the .NET Framework (which is the hottest framework in my opinion), you were used to adding several buttons that preview different user controls as follows:
1) First you would prepare an appropriate user interface (contains 3 buttons and a single panel on the right area to view each user control after clicking one of the added buttons).
2) Adding 3 user controls from the solution explorer...
3) Inserting the content on each user control...
4) Implementing code for the 3 buttons on the frmMain.cs as the following (for this implementation we will be implementing the "Welcome" button carrying the object name as welcomeBtn, and the rest will have identical code but different user control names instead):
private void welcomeBtn_Click(object sender, EventArgs e)
{
//Clear up everything from the panel if any item exist(s)...
mainPanel.Controls.Clear();
//Create a new instance of a user control for the button...
UserControl1_Welcome welcome = new UserControl1_Welcome();
//Show up the created instance of the user control
mainPanel.Controls.Add(welcome);
}
5) Finally, the program will end up initially like this when running:
http://i.stack.imgur.com/OENwG.png
** Usage of the program **
When you click on the "Welcome" button for example, the result should be expected to be like this:
http://i.stack.imgur.com/iCyo3.png
... and when you click on a different button, lets say "License Agreement" button, you would expect to see something other than your current selection.
MAIN QUESTION
How can we bring the simplicity of Windows Forms in QT CREATOR by applying the "QDockWidget"?
I have tried inserting the QDockWidget component with no problems, but when I try to do the equivalent .NET code for adding the QWidget inside the QDockWidget:
ui->dockWidget->setWidget(myWidget);
which I think is equivalent to this line of code in C#.NET (correct me if I'm wrong here):
ui.Controls.Add(myWidget);
After using this code, my program won't crash nor shows anything running...
P.S. I'm sorry for linking the images, I don't have 10 reputation for making them show up...
What I want is to have a program that does the same thing with the C# example (showing a user control based on the click of a button).
If you want to show a particular widget based on a button click, I suggest to use a QStackedWidget
A simple example would be like this:
// In the constructor of your CustomWidget
// Create your buttons
QPushButton* firstButton = new QPushButton("First Button", this);
QPushButton* secondButton = new QPushButton("Second Button", this);
QPushButton* thirdButton = new QPushButton("Third Button", this);
// Create your (custom) widgets
QLabel* firstPageWidget = new QLabel("First Label", this);
QLabel* secondPageWidget = new QLabel("Second Label", this);
QLabel* thirdPageWidget = new QLabel("Third Label", this);
// Add them to the stackWidget
/*QStackedWidget* */ m_stackedWidget = new QStackedWidget(this);
m_stackedWidget->addWidget(firstPageWidget);
m_stackedWidget->addWidget(secondPageWidget);
m_stackedWidget->addWidget(thirdPageWidget);
// Insert buttons and stackWidget to CustomWidget
QVBoxLayout* layoutStack = new QVBoxLayout();
layoutStack->addWidget(m_stackedWidget);
QVBoxLayout* layoutButtons = new QVBoxLayout();
layoutButtons->addWidget(firstButton);
layoutButtons->addWidget(secondButton);
layoutButtons->addWidget(thirdButton);
QHBoxLayout* layout = new QHBoxLayout();
layout->addLayout(layoutButtons);
layout->addLayout(layoutStack);
setLayout(layout);
// Connect button clicks to slots
connect(firstButton, SIGNAL(clicked()), this, SLOT(onFirstButtonClicked()));
connect(secondButton, SIGNAL(clicked()), this, SLOT(onSecondButtonClicked()));
connect(thirdButton, SIGNAL(clicked()), this, SLOT(onThirdButtonClicked()));
Then you change the currently visible widget in the slots:
void CustomWidget::onFirstButtonClicked() {
m_stackedWidget->setCurrentIndex(0);
}
void CustomWidget::onSecondButtonClicked() {
m_stackedWidget->setCurrentIndex(1);
}
void CustomWidget::onThirdButtonClicked() {
m_stackedWidget->setCurrentIndex(2);
}
Note that if you want the button clicks just to simply change some text (as opposed to change the visible widget), you probably better use a QTextEdit instead of a QStackedWidget, and in the slots call setText("....");
If you have a lot of buttons, you'd better use QSignalMapper to limit the number of slots.
Also, I didn't get why you mentioned QDockWidget since they have a quite specific usage:
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-level window on the desktop.
QDockWidget provides the concept of dock widgets, also know as tool palettes or utility windows. Dock windows are secondary windows placed in the dock widget area around the central widget in a QMainWindow.
If you simply want a separate window, you're probably looking for a QDialog
How to do this with QtDesigner:
First you would prepare an appropriate user interface (contains 3 buttons and a single QStackedWidget on the right area to view each user control after clicking one of the added buttons).
Adding 3 pages for the user controls in the stack (+ one for the "empty" page if you really need that). If you want to design the Controls in separate UI Files / Only in Code (instead of all controls in your MainFrame), you would add plain QWidgets and promote them to the appropriate specific widget type
Inserting the content on each user control...
Implementing code for the 3 buttons on the frmMain.cpp/.h as the following (for this implementation we will be implementing the "Welcome" button carrying the object name as welcomeBtn, and the rest will have identical code but different user control names instead):
void FrmMain::on_welcomeBtn_clicked() {
ui->stack->setCurrentWidget(ui->welcomeWidget);
}
Select the "empty" page at as the current page in the designer, so the program will end up initially like this when running: (your screenshot)
When you click on the "Welcome" button for example, the result should be expected to be like this: (your second screenshot)
In my opinion, Miki's answer is the only correct approach to this use case (using a QStackedWidget).
For sake of completeness, I'll demonstrate how the same Clear and Add method as used in .NET is done in Qt:
// Assume controlPanel is a QWidget where you want to place the items
// Assume that controlPanel has set a layout (e.g. QHBoxLayout)
// Clear: Remove all Items from layout
QLayoutItem *child;
while ((child = controlPanel->layout()->takeAt(0)) != NULL) {
delete child;
}
// Now widgets are still there, but not layouted. Delete them explicitly
foreach (QWidget * w, controlPanel->findChildren<QWidget*>()) {
w->deleteLater();
}
// Now controlPanel is cleared
// Add new control
controlPanel->layout()->addWidget(new MyNewControlWidget);
First is, we can not force how other framework works to another one. Each framework has its flow and design.
What I am understand is you want to show another widget to the main window.
If you want to use the QDockWidget, its says on the documentation like this :
void QDockWidget::setWidget(QWidget * widget)
Sets the widget for the dock widget to widget.
If the dock widget is visible when widget is added, you must show() it explicitly.
Note that you must add the layout of the widget before you call this function; if not, the widget will not be visible.
Please share here you code of myWidget, so we can try to help you to figure out what is wrong.
On my side, I can achieve it by add the QVboxLayout on your ui->dockwidget and add QLabel with emtpy string and when you want to show myWidget just call ui->dockwidget->vboxlayout->replaceWidget(label, myWidget);
I'm currently working on refining an app I made for (currently only) IOS. In this app, I have 15 different UIViewControllers, each one of them shows different data and uses different objects.
My menus have a hierarchical structure (not binary). I have 4 "parent" ViewControllers. These parent ViewControllers each have 1 or more "child" ViewControllers:
Roster
EventDetails
Directions
MapView
ChangeRequests
NewChangeRequest
ChangeRequestDetails
Contacts
ContactDetails
ProgressReport
NewReportEntry
DoubleChecks
NewDoubleCheck
DoubleCheckDetails
DoubleCheckPhotoDetails
On the parent ViewControllers I use a FlyoutMenu (with datasource) to be able to navigate to other parent ViewControllers. On the child ViewControllers I have a custom back button, with a delegate attached to it, to take me back to the previous menu. Here come the problem.
I've been given the assignment to link some menus to each other, to improve user-friendliness. an example:
I'm currently at the EventDetails menu. In this menu, I want a button to take me to the NewDoubleCheck menu. Both of these menus have a back button, that uses PopViewController to navigate back to the previous menu. If I'd accessed NewDoubleCheck from DoubleChecks, it would take me back to DoubleChecks. But if I'd accessed it from EventDetails, it takes me back to EventDetails, because it's on the top of the stack. This means I end up in an endless loop of EventDetails --> NewDoubleCheck --> EventDetails --> NewDoubleCheck.
Long story short: I want to be able to search the stack of ViewControllers and be able to select the right ViewController to be loaded, using PushViewController.
I was thinking about writing a method at the start of my app (somewhere near the initialisation of my FlyOutMenu, I'd reckon, that would make me an array of Dictionary<string, UIViewController> with ALL of the ViewControllers in my project, so I can search and navigate more easily. Is this possible?
I know this is a long text, but I'd be glad to hear any opinions and solutions for my problem.
Thanks in advance.
Dear regards,
Björn
I encountered the same problem in one of my apps.
Funny thing is that I checked some of the 'famous' apps on the store, and I noticed that they have this 'endless loop' issue.
My solution was:
Before navigating to NewDoubleCheck, I'd search if it already exists in the navigationController stack.
If that's the case, then I pop to that viewController instead of pushing a new one.
Something like this:
if ([self.navigationController.viewControllers[[self.navigationController.viewControllers count]-2] isKindOfClass:[NewDoubleCheck class]]) {
// ViewController already exist, so we need to get back to it
NewDoubleCheck *viewController = (NewDoubleCheck *)self.navigationController.viewControllers[[self.navigationController.viewControllers count]-2];
[self.navigationController popToViewController:viewController animated:YES];
} else {
// Push to NewDoubleCheck
}
Yes you can get all view controllers like this
NSArray *controllerArray = [[self navigationController] viewControllers];
for (UIViewController *controller in controllerArray){
NSLog(#"%#",controller.title);
}