c# - create invisible user control - c#

I need to create a user control in C#.Net, which can be added to the application without being visible - just like the FolderBrowserDialog. It's a new window which I'll be using often so I think this is the right way. The window will be opened by envoking the showDialog-Method as known from the other dialog.
Any Idea?
Thanks and regards,
Daniel

Since all these "invisible" controls derive from Component class, you should start by reading the MSDN article on it: http://msdn.microsoft.com/en-us/library/system.componentmodel.component.aspx.

simply set Visible to false or isn't this what you're asking for ?

A UserControl is by definition not a Form; I think what you really want is a Component. That said, couldn't you really just create a new Form class that has the functionality you want? Whenever you want to display it, create a new instance and call ShowDialog. Or, if you want to preserve state, add an instance as a class member to your parent form, call its Show method whenever you want to display it, and add an event handler to its FormClosing event to check:
if (e.CloseReason == CloseReason.UserClosing)
and, if so,
e.Cancel = true;
Hide();
(This last part is to prevent errors if the user closes the form and then tries to display again after it's been disposed.)

I think more information may be needed, but if your crating a custom user control, the control should have a .Visible property. The follow is an example of how a button can be located on the form but hidden from a user.
button.Visible = true; // shows the button
button.Show(); // Shows the button
button.Visible = false; // hides the button
button.Hide(); // Hides the button
While the button may still be on the form/control, it will not be interactible by the user. You can still perform programmatic control on the button, but essentially it is not a user control while it is 'hidden'. If you want there to be a sort of hidden button that the user can click you will need to do other things to obtain this but It doesn't should like that is what you want.

This show/hide thought process sounds a lot like pains and confusion leftover from classic VB. The old form methods of show and hide, etc., were confusing and often left me as a developer in a position to not know whether an object existed or if was merely invisible. And checking was only trivial if you used On Error Goto to prevent a null reference. So right off I would advise not to think in terms of visibility unless you are doing something with a web page and need to maintain space and state.
First, create a Windows form and add it to your project, assuming that is the type of project that you are describing. Decorate the form with the proper controls, and where applicable, create properties to allow public access to the control values. Also set the DialogResult property of the buttons that either "OK" or "Cancel" the form. Give it an appropriate border style of either Fixed3D or FixedDialog. Maybe also set the property for where you want the form to appear on startup -- center parent, center screen, Windows default, etc. The event handlers for both "OK" and "Cancel" should invoke this.Close(); to close the window.
From the calling point in the code, here's some hypothetical code to get you going in the right direction. Write something like this in the place where you want to invoke your Dialog.
int intResult = 0;
string strResult = null;
MyDialogForm frm = new MyDialogForm();
frm.Title = "Select an Item";
frm.SomeProperty = 0;
frm.SomeOtherProperty = true;
if (frm.ShowDialog() == DialogResult.OK)
{
intResult = frm.Result;
strResult = frm.StringResult;
}
else if (frm.ShowDialog() == DialogResult.Cancel)
{
// User clicked the cancel button. Nothing to do except maybe display a message.
MessageBox.Show("Canceled Task");
}
...
// Somewhere further on down, but within scope, simply repeat
// what you just did, but without having to reinstantiate the
// form Window. But if you make it that far within the same
// scope, this method might be too busy and may need to be
// factored down.
So in short:
Scrap show/hide -- its not a good
practice.
Save the form data without
using an invisible form to save it;
that's the class's job.
If the UI requires a lot of flipping back and
forth between windows, check your
design for other alternatives for
solving the original problem. Maybe a design pattern such as MVC is for you, depending upon the size and complexity of your application.
Sound good?

You can put that control in a Panel. Set the panel height = 0 visible = false when you dont want to show the control.
And do the vice versa when you want to show it.

Derive from Control, not UserControl, and in the constructor set Visible = false.
Also create an event handler in the constructor.
VisibleChanged += new EventHandler(SetVisibleFalse);
Create a method named SetVisibleFalse.
private void SetVisibleFalse(object sender, EventArgs e)
{
if (Visible) Visible = false;
}

Related

How to edit the contents of a window from another window in WPF

In my program I have two windows, the first one being my main window with a text box and the second one having an entry field with a button to update the text box in the first window. I'm a beginner in terms of using WPF and coding in C# in general, but is there a way to pass a pointer or reference of my main window to the second window so the second window can edit the text box of my first window? Is that even the right way to think about solving this issue?
WPF assumes you are binding your forms to a ViewModel object. This object can be bound to more than one form to give you different views and capabilities, so in this case you'd bind the same ViewModel to both forms, and what is changed in your edit form will appear automatically in your main form.
Your question is a bit vague and there are many approaches to accomplishing this. MVVM as Steve Todd mentions, is one.
However, it sounds like you simply want to open the window as a dialog. In your second window's code behind, be sure your textbox has a name in XAML and then access it create and easily accessible property that gets and sets your textbox value.
public MyTextContent
{
get => this.MyTextBox.Text;
set => this.MyTextBox.Text = value;
}
You can control the return value based on conditions (such as OK or Cancel buttons) if you like by using click events. The window contains a DialogResult property. The default is false, so you will need to set this somewhere.
this.DialogResult = true; // OK
Then in your main window's code behind, create a new instance of the window, assign it's property and show it. This will need to be done during a click event of a button or some similar trigger
var myDialog = new MyDialogWindow()
{
MyTextContent = "Textbox Starting Value";
}
bool? result = myDialog.ShowDialog(); // Returns when the dialog window is closed.
if(result != null && result)
{
this.LocalTextBox.Text = myDialog.MyTextContent; // Copy the text to the main textbox.
}
Typically you do this in data context of your main window. You use IoC to pass an instance of popup notification service in the constructor and create a private reference. You call that service method that displays the popup notification where user can enter async (and await) for its response or use reactive extensions to subscribe to submit action of that button. A thing to look out for is that you can update ui only in dispatcher thread and do not forget to dispose the subscription after you have finished using the window.

Docking an existing QWidget in QWindow

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);

C# change page/screen?

How do you change page/screen display in c# windows forms without using Close(); and Show(); ?
Close(); and Show(); makes the screen blink and I want it to be fluent. Can I use the menustrip to change screen ?
You can create the new window at exactly the same size and position as the original, and then do a ShowModal on it. When the new window closes, though, you will be back to the original window.
You can make it the same form, but display the controls of each window in different tab pages of a TabControl. I'm not sure offhand how to hide the Tabs which allow the user to change TabPage but I think it can be done; or it might be a good thing to have them there, depending on your requirements.
You can do the Show as you are doing currently, but don't do the Close() of the original form. Instead, when the original form creates the new one, it should subscribe to an event (Activated? or create a special one fired by the new window when it's finished displaying itself) and when it receives that event it calls Close() on itself.
There's three possible ways.

How to make changing "screens" in c#

I'm new in C#, and I wanted to know if there was any way to show a screen with certain elements, and then with the click of a button, switch to another screen, similar to an installer.
From my experience in Java, I would just use a few JPanels and then hide only the one i want visible.
However, I'm new to C# forms and it's very different from Java swing. Anyone understand my problem and can tell me pretty much how this works? Thanks.
Simple approach
Just use a Grid with multiple Grids inside of it. Set the Visibility property of each internal Grid (except the first one you want to show) to Hidden or Collapsed, and then set them to Visible when you want to display them.
Better approach
Create a class for each section, each of which derives from the same parent class. Create a DataTemplate for the parent class, then just have instances of the template load into the original Grid through a ContentPresenter.
You can try this creating new forms. From my experience I've tried this:
Form2 formTwo = new Form2(); // creates instance
formTwo.Show(); // displays the new form
this.WindowState = FormWindowState.Minimized; // minimizes previous form
this.ShowInTaskbar = false; // hides it from taskbar
Keep in mind that this does not close the previous form. I would recommend setting ShowIntaskbar as True if you don't mind the user seeing the form minimized.
EDIT: If you want to show new elements I suggest you can try adding a new Form class to the project then using the designer.

Why calling Hide in a child form's FormClosing event handler hides the parent form?

When Form2 is closed, via it's X button, the Main form is sometimes hidden as well, but not always. Often times the Main form is hidden after initial 'newForm' button click and other times many open-close operations are required before the Main form gets hidden on Form2's closing. Why is this happening? Why is it irregular?
This is a small test code for a larger application I'm working on. In that application a thread continuously reads the network stream and when a particular message is encountered a modal form is displayed. The user can close that modal form or it can be told to close itself by a different network message. In this event, to give the user some time to view the data that the form is displaying I implemented a delayed form closing for that form. When the form is running its delay closing code, another message can come in over the network that will open up a new instance of this form in which case, I observed, that once the timer of the original form runs out, the original form is left displayed until the new instance is closed. Calling Hide in the FormClosing event handler closes the original form if more than one instances of it are running, but it has this side effect of hiding the entire application (the Main form) when the last instance of this form is closed, either by the user or by the delayed closing code. And again, the entire application is not always hidden, but it does happen.
//Main form's 'newForm' button
private void btn_newForm_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.ShowDialog();
}
public partial class Form2 : Form
{
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
Hide();
}
}
Update (from the application I'm working on):
The problem is shown visually below. The top part of the picture, labeled "A", represents the situation where the first modal dialog (greyed out) was instantiated and it is in the process of being auto closed after 4 seconds have elapsed. The second instance (blue window heading) is active and awaiting input. In the lower part of the picture, labeled "B", the counter to closing of the first instance has completed, yet the first instance remains visible. Adding Hide does not change picture "A" but picture "B" would only be showing the active modal dialog, which is what I want. If Hide is not used and we have the case shown in "B", once the active modal dialog is closed the inactive dialog will disappear together with the active one, but no sooner. At this time my main form will be hidden as well, sometimes.
Your main form doesn't get hidden, it disappears behind another window. The flaw in your code is that for a brief moment none of your windows can get the focus. Your main window can't get the focus, it got disabled by your dialog and won't get re-enabled until the dialog is fully closed. Your dialog can't get the focus, you hide it. So Windows goes looking for another window to give the focus to and can only pick a window owned by another application. Like Visual Studio, nice and big so your main window is well covered by it.
Not sure what you are trying to do, it doesn't make sense to call Hide() since the dialog will close a couple of microseconds later. Just delete the statement.
I am not sure if I am right but maybe you forgot to add e.Cancel = true; to your closing event.
Second, I think using a modal form is only usefull when you expect an action like OK or CANCEL from user, that is where DialogResults comes handy. It sounds strange if this happens time to time not all the time! maybe you can try like this:
//Main form's 'newForm' button
//Define form in your mainform
private Form2 f;
private void btn_newForm_Click(object sender, EventArgs e)
{
if(f != null) { f.Show(); return; }
f = new Form2()
f.FormClosing += delegate { f.Hide(); };
f.Show();
}
I know the topic is quite old, but I recently had to look for answers for this precise question.
Why hiding the (child modal) form instead of closing it ?
I may be wrong, but I think that in some cases, hidding the modal child form instead of closing it is sometimes useful.
For example, I'm using a class that is a custom tree of grids. Think of something like an Excel Document with multiples tables (sheets) and each table can have child tables. A very powerful manner to store datas that can be used by multiple objects and multiple forms at a time.
Now, this "TreeTable_Class" object has an inbuilt custom form that actually shows the content of one of its tables at a time in a GridView, and you can select which table to show by selecting it in a Treeview. You can see here that the "Database Editor" is actually and MDI Form that can load the Form from any TreeTable_Class.
And this is the Form I use to edit the content of a Cell for a given (selected) Table (I've chosen another cell with long text content from another table in this database)
Now, when you choose to close the custom form instead of hiding it, that form will be unaccessible, you can't show it anymore, and you get an exception (no instance of the object) Somewhat, it isn't disposed yet (so the check If MyForm Is Nothing Then... is useless) I know I have to implement the GarbageCollector and dispose the Child Form manually, but it's outside the scope of this topic.
Anyway, my class could use a large amount of memory, of datas, and if I had to rebuilt ALL the contents each time I want to show a new instance of that form, that would be a large amount of workload in my application. That's why I have chosen to hide the form instead of closing it until the main application exits or when a specific CloseFormAndDispose() method is explicitly called, either by the program, or if I make this option available for the user via an user interface.
Workaround try :
This is the workaround I've found to override the "form replaced by another because none of the parent/child ones could be retrieved" :
Sorry, I'm in VB.. but you can use a tool to convert this to C#, or do it manually, it's pretty simple..
// This is the child, a Cell Editor that can edit the content of a Cell.
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
This Editor form is a member of TreeTable_Form, a form that can actually show and edit the content of the whole Database File (a single file)
And this TreeTable_Form class contains a routine that handles CellEditor closing event
Public Partial Class TreeTable_Form
// Sorry. The "WithEvents" in C# is a litte bit complex to me... So, in VB :
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
// ...
// CellEditor handling method (I used a Code converter...) :
// The original VB declaration is :
// Protected Sub RecallFormAfterCellEditorHidden() Handles _CellEditor.Closed
// You'll have to write specific Event handler for _CellEditor object declared above...
protected void RecallFocusAfterCellEditorHidden()
{
Application.DoEvents();
this.Focus();
}
End Class
This tiny protected void RecallFormAfterCellEditorHidden() method in your Class (if you are using a class that contains Forms) or in your Main From, assuming that your main form contains the child forms (dialogs) will try to force the focus on your Application or MainForm...
By the way, TreeTable_Form is actually a component of TreeTable_Class. The later is an object that can be used anywhere you want. In a Main Form Application, in another Class, in a dialog, anywhere... and could be passed by reference to share its contents between several items. And this TreeTable_Class contains a RecallFocusAfterTreeViewerHidden() method that handles the closing of that form. That means, the Form or Application that actually uses the class will get the focus each time you close the its child Form. I've made it that way to get an object that could be used anywhere
We still get problems !
However, this method will make your application flicker a bit each time you close your child dialog, and doesn't succeed at 100% ! Sometimes, my parent form still disappear from screen and gets struck behind another window. Alt+TAB wont helt either. But this happens less than without this method trick. I don't have any better answer at this time, still searching... I'll come back here if I find out how. I'm using this custom made application in my work to write memos during meetings for example, and produce PV (procès verbal - french sorry) in PDF or DOCx on the fly...
And I'm sorry, I'm in VB, not C#. Hope this helps a little, until we find a better workaround for this...

Categories

Resources