I want to create a custom MessageDialog which in terms of its interface is exactly the same as the provided MessageDialog except for one thing; The Content property acts like that of a ContentControl so I can place custom UI elements in it.
Though I cannot for the life of me figure out how the developers were able to create a class that could be 'shown' in the UI without specifying that it inherits from any sort of control in the framework.
How is it possible to create a regular class and specify its 'Template' in code?
Thank you
You can accomplish this by creating a Popup, set it's Child. and then open it. You can create any XAML controls in code, so this is not an issue.
Popup popup = new Popup { Child = CreateXamlControlInCode() };
popup.IsOpen = true;
For step by step instructions, see this blog post.
Related
I just started working with Visual Studio C# and to be honest I didn't fully understand what happens when we chose to hide a form or a user control.
My intuition tells me this hide/show method is kind of "inefficient" way to get an user through all the functions of my app.
So I am asking you guys if there is another workaround to "load" user control parts in a form.
Right now my main_menu form has all the user control objects placed on the form, but hidden, and I am using buttons to show them.
Is there a better way to achieve the same result? (I was thinking of a workaround like having an empty panel where I can load the User Control - not sure if possible)
Thank you!
You can create the controls on the fly and add them to or remove them from the Controls collection. On the class level, define this field
private Control _currentPanel;
You can use a more specific type here, if you are deriving all your panels from a common base type.
Then change the panel with
// Remove previous one.
if (_currentPanel != null) {
Controls.Remove(_currentPanel);
}
// Add new one
_currentPanel = new MyNewPanel();
//TODO: possibly set the panels Docking property to Fill here.
Controls.Add(_currentPanel);
In the example I am working with the form's Controls collection; however, you might have to use the Controls collection of some container control holding the panel.
When using code behind, the code looks like this:
AnotherWindow x = new AnotherWindow();
x.Show() ;
// or x.ShowDialog()
But how can I achieve this using MVVM? Specifically Prism?
In case you need to build a dialog for asking user login input or progressing dialog, MahApps.Metro can be a useful toolkit as it provides you with some built-in dialog UI/functionalities with MVVM pattern. For more information, check some examples here:
https://mahapps.com/controls/dialogs.html
In Prism, there's the InteractionRequest for short-lived dialogs. If you're looking for a long living dialog, like a second application window or shell, you're stuck with new Window ... Show.
To make your dialog service mvvm-friendly, you should hide it behind an interface and make it as generic as possible. Using view model first here eliminates the need to specify a window type, because you can provide a default window that just contains one large ContentControl, and the view can be mapped as DataTemplate.
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);
Is it possible to go to next window or go back to a window using just <window> tag. I searched through internet and didn't find it anywhere. Whenever navigation is needed, I found <Window.Navigation> is in use. But using but this browser like tab on top I want window to navigate when I click m Ok or cancel button on my <Window>.
P.S. I am new to WPF. So I don't know much about it.
If NavigationWindow would work for you except for the navigation tab on top, the simplest thing to do is set ShowsNavigationUI=false. Alternatively (a bigger hammer, but more flexible) you can replace the Template on your window and that will also remove it.
It is possible to navigate by using the Window class, but it depends what you want to achieve. You can assign your newly created Windows to the applications MainWindow.
EDIT: I did some tests: Other than the documentation states you cannot assign a new Window to the MainWindow property like this:
Application.Current.MainWindow = new MyWindow(); // does not work!
The main window is special, when it is closed the application will normally be closed.
However it might be easier to use the class as it has a NavigationService property which makes navigation a easier. You finde some documentation under http://msdn.microsoft.com/en-us/library/ms750478.aspx
I've seen two threads here about TDI & C#. Both of them didn't really answer the questions I have ...
Since TDIs are pretty much like a standard nowadays, I can hardly imagine, that I have to buy a special control (like AvalonDock or SandDock).
This must be possible with built in the tab-control(?) somehow! I don't need special features like dock- and draggable tabitems. Just open every form in a new tab. Thats it.
Like putting every forms content controls into user controls and by request (button, menu click ...) add a new tab and put the corresponding user control on it ... something like this.
How would you do it? This can't be THAT complicated (even for me) or am I missing something?!
thanks a lot!
Maybe Josh Smith's article on MVVM can give you an idea how to design such user interface. Example being built there is kinda tabbed document interface so you can use it as a starting block.
It's not that hard. It seems hard because there are a lot of different ways to do it.
Try this:
<TabControl x:Name="documentArea"/>
Handler for AddForm button:
private void AddFormClick(object sender, RoutedEventArgs e)
{
object form = GetNewForm();
documentArea.Items.Add(form);
}
That's it. You have to implement GetNewForm() in one of two ways. Have it return a user control that displays the form.
OR better yet, have it return your document that you want to display. Use a DataTemplate to select the controls to use for displaying this document. This method is going to be more complex to set up.