If I have a Xaml Window, how does one open it as a child window, and then have the parent window wait for the child to close before the parent window continues executing?
Did you try showing your window using the ShowDialog method?
Don't forget to set the Owner property on the dialog window to the main window. This will avoid weird behavior when Alt+Tabbing, etc.
A lot of these answers are simplistic, and if someone is beginning WPF, they may not know all of the "ins-and-outs", as it is more complicated than just telling someone "Use .ShowDialog()!". But that is the method (not .Show()) that you want to use in order to block use of the underlying window and to keep the code from continuing until the modal window is closed.
First, you need 2 WPF windows. (One will be calling the other.)
From the first window, let's say that was called MainWindow.xaml, in its code-behind will be:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
Then add your button to your XAML:
<Button Name="btnOpenModal" Click="btnOpenModal_Click" Content="Open Modal" />
And right-click the Click routine, select "Go to definition". It will create it for you in MainWindow.xaml.cs:
private void btnOpenModal_Click(object sender, RoutedEventArgs e)
{
}
Within that function, you have to specify the other page using its page class. Say you named that other page "ModalWindow", so that becomes its page class and is how you would instantiate (call) it:
private void btnOpenModal_Click(object sender, RoutedEventArgs e)
{
ModalWindow modalWindow = new ModalWindow();
modalWindow.ShowDialog();
}
Say you have a value you need set on your modal dialog. Create a textbox and a button in the ModalWindow XAML:
<StackPanel Orientation="Horizontal">
<TextBox Name="txtSomeBox" />
<Button Name="btnSaveData" Click="btnSaveData_Click" Content="Save" />
</StackPanel>
Then create an event handler (another Click event) again and use it to save the textbox value to a public static variable on ModalWindow and call this.Close().
public partial class ModalWindow : Window
{
public static string myValue = String.Empty;
public ModalWindow()
{
InitializeComponent();
}
private void btnSaveData_Click(object sender, RoutedEventArgs e)
{
myValue = txtSomeBox.Text;
this.Close();
}
}
Then, after your .ShowDialog() statement, you can grab that value and use it:
private void btnOpenModal_Click(object sender, RoutedEventArgs e)
{
ModalWindow modalWindow = new ModalWindow();
modalWindow.ShowDialog();
string valueFromModalTextBox = ModalWindow.myValue;
}
Window.Show will show the window, and continue execution -- it's a non-blocking call.
Window.ShowDialog will block the calling thread (kinda [1]), and show the dialog. It will also block interaction with the parent/owning window. When the dialog is dismissed (for whatever reason), ShowDialog will return to the caller, and will allow you to access DialogResult (if you want it).
[1] It will keep the dispatcher pumping by pushing a dispatcher frame onto the WPF dispatcher. This will cause the message pump to keep pumping.
Given a Window object myWindow, myWindow.Show() will open it modelessly and myWindow.ShowDialog() will open it modally. However, even the latter doesn't block, from what I remember.
Related
I want to open a window if a button is clicked, and that button is located in another window.
So how to check whether a button in another window is clicked or not?
Now I am coding in a class called 'RightButton.cs'
I want to open a window called 'PopUp' when 'Add' button in 'Reason' window is clicked.
PaidOutReason paid = new PaidOutReason(trnprt, apiParameters);
paid.ShowDialog();
if (paid.btnSave.ClickMode == new ClickMode())
{
PopUpBanks popu = new PopUpBanks(this);
popu.Show();
}
This one was working perfectly, but I had to remove ShowDialog() and replace it with Show(). Then it was not working.
This is for a POS system. It has a user Control called 'Keyboard'. When the 'Reason' window is opening this Keyboard also want to be opened. Therefore I had to replace ShowDialog() with Show().
I'd add an event to the window, and bind an event handler to it.
class WndWindow{
BtnPaid_Click(object sender, EventArgs e){
using(var paid = new PaidOutReason()){
paid.BtnAddClick += Paid_BtnAddClick;
paid.ShowDialog();
paid.BtnAddClick -= Paid_BtnAddClick;
}
}
Paid_BtnAddClick(object sender, EventArgs e){
var popu = new PopUpBanks();
popu.Show();
}
}
class PaidOutReason{
public event EventHandler BtnAddClick;
BtnAdd_Click(object sender, EventArgs e){
//Do standard event handler code
BtnAddClick?.Invoke(this, e);
}
}
If there's any sort of checks you need to perform you can do that before reading the event, and simply return if checks fail.
You can use static controlls in your app. Start with declaring static window object in App.xaml.cs, for example
public static PaidOutReason paidOutWindow;
then, in App constructor method, after InitializingComponent(), initialize static window class:
paidOutWindow = new PaidOutReason();
You may wonder what it gives to you. Since it's POS application, you are likely to use the same set of windows quite often and repeatedly, means you can hold window object in memory and refer to it (and change, when needed). Also, after doing such thing, you will have access to all structures inside PaidOutReason object, by typing
App.paidOutWindow.FunctionName();
and finally, you should have access to all window functions such as ShowDialog().
If you are using MVVM pattern, then you can use command binding for showing the PopupBanks window.
For example:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ICommand AddCommand { get; set; }
public ViewModel()
{
AddCommand = new RelayCommand(AddCommandHandler);
}
private void AddCommandHandler()
{
IPopUpBanks popu = new PopUpBanks(this);
popu.Show();
}
}
PaidOutReason view:
1. <Button x:Name="Add" Command={Binding AddCommand}/>
2. Set the above viewmodel as datacontext of PaidOutReason view.
Create a interface IPopUpBanks containing Show() method and implement this interface on PopUpBanks view.
Handle the Click event of btnSave:
PaidOutReason paid = new PaidOutReason(trnprt, apiParameters);
paid.btnSave.Click += (ss, ee) =>
{
PopUpBanks popu = new PopUpBanks(this);
popu.Show();
};
paid.Show();
Instead of the Keyboard Window, I made it a user control and then initialized an event in there. Then I insert that Keyboard User Control to the PaidOutReason Window and then called the event. Then I was able to use ShowDialog() to call the window.
After closing a form, I can't access it anymore, because the object does not exist anymore.
Is there a way to avoid this kind of behaviour, without initiating the object everytime I perform an event?
This is the first Form called status, it's not the only one I need to create, that's why Iam asking.
This does not work: After closing the form and click on the menu item I get an reference error "Object does not exist", and therefor can't be accessed.
public partial class Main : Form
{
StatusForm statusForm = new StatusForm();
public Main()
{
InitializeComponent();
statusForm.MdiParent = this;
}
private void statusToolStripMenuItem_Click(object sender, EventArgs e)
{
statusForm.Show();
}
private void Main_Load(object sender, EventArgs e)
{
statusForm.Show();
}
}
If you use Close to close a form, it is unusable after that point. You have to create a new one.
However, if you want a persistent Form object, just call Form.Hide instead. This hides the form but leaves it "open".
MSDN notes this as well:
When the Close method is called on a Form displayed as a modeless
window, you cannot call the Show method to make the form visible,
because the form's resources have already been released. To hide a
form and then make it visible, use the Control.Hide method.
The question implies I'm brand new to WPF, and I am having a lot of problems so far transitioning from winforms.
What I'm trying to do is a very simple concept, but I'm spinning in circles trying to get it to work. I want to have a textbox on my MainWindow update from a property on my 2nd window. However, this window is not open all the time.
In MainWindow, I open up a new window from an event like so:
private void menuChangeSerialPort_Click(object sender, RoutedEventArgs e)
{
ChangeSerialPort changeSerialPort = new ChangeSerialPort();
changeSerialPort.Show();
}
The purpose of the new window is to give the user the option to change serial ports. I scan them and put them into a combo box. Upon selecting one and confirming (pressing an 'OK' button), I want to send back the string of the serial port name for the MainWindow.xaml to use in the future. I close my 2nd window after that:
public partial class ChangeSerialPort : Window
{
public ChangeSerialPort()
{
InitializeComponent();
// Used with XAML, the owner is set so the opening position is centered according to where the Main Window is.
this.Owner = Application.Current.MainWindow;
// Scan and list port names
GetSerialPorts();
}
private string _portname;
public string serialPortName { get { return _portname; } } // Readonly property
private void serialPortOKBtn_Click(object sender, RoutedEventArgs e)
{
txt_noSerialSelected.Visibility = Visibility.Hidden;
if (cmbbox_serialPortList.SelectedItem == null)
{
txt_noSerialSelected.Visibility = Visibility.Visible;
}
else
{
_portname = cmbbox_serialPortList.SelectedItem.ToString();
//
// WHAT TO PUT??
//
this.Close();
}
}
I cannot for the life of me get data binding to work. I understand this is the proper way, but I have spent a number of hours reading and getting no where. My backup plan is to access the data from a property. But I do not know how to access any properties back on MainWindow, or vice versa (because the window will close after the selection is confirmed). So I'm 0/2.
Can anyone help me out? And possibly explain in very simple terms how databinding could help me out in this scenario? For instance, what are the steps to take and what exactly would go into the textbox xaml on my MainWindow?
<TextBox x:Name="serialPortInUse" Text="?????????" HorizontalAlignment="Right" Margin="0" VerticalAlignment="Top" Height="20" Width="86" TextChanged="serialPortInUse_TextChanged" BorderThickness="0"/>
Thanks in advance!
Any number of ways of doing this, but the simplest (from your POV) is:
The second window raises an event when the port is selected. The
eventargs would contain the name of the selected port.
When the main window creates second one, it subscribes to the event,
using a new method to receive the event.
When the main window receives the event, set sets the text of
serialPortInUse
This is fine for a little app (in the sense of not many windows) as this looks to be. In more complicated apps, I recommend you use the MVVM pattern. There is a very good book about it, Advanced MVVM, which has been around a while now but is still a superb introduction. With MVVM you can use frameworks like MVVMLite - which you can also install via NuGet install-package MVVMLight - which has a Messaging system built in which decouples senders from listeners and would be a natural in this situation.
Add a ref parameter in your ChangeSerialPort window;
public partial class ChangeSerialPort : Window
{
TextBox textBox;
public ChangeSerialPort( TextBox myTextBox)
{
InitializeComponent();
textBox = myTextBox;
}
}
Pass that textbox
private void menuChangeSerialPort_Click(object sender, RoutedEventArgs e)
{
ChangeSerialPort changeSerialPort = new ChangeSerialPort(serialPortInUse);
changeSerialPort.Show();
}
set the text value
private void serialPortOKBtn_Click(object sender, RoutedEventArgs e)
{
txt_noSerialSelected.Visibility = Visibility.Hidden;
if (cmbbox_serialPortList.SelectedItem == null)
{
txt_noSerialSelected.Visibility = Visibility.Visible;
}
else
{
_portname = cmbbox_serialPortList.SelectedItem.ToString();
textBox.Text = _portname;
this.Close();
}
}
In my application (WPF) i have this window:
public partial class Window1 : Window and in the Xaml x:Class="WpfApplication1.Window1"
Now, when i switch to and from the main to window 1 and back, i us the Visibility.Hidden and Visibility.Visible to hide them and make them show again to the user.
What i try to do now, is make a test button in the main window, that says: Close Window1.
This window is hidden, but i really want to close it in the background.
at first i though to just use the Window.Close(); but that does not seem to do the trick.
So, how should i do this in a correct way ?
Thank you very much in advance.
EDIT 1 - making question more clear
To open the window1 in my Main window, i use this part
Window1 W1 = null; // Initialise Field.
public void CalcTabel_Click(object sender, RoutedEventArgs e)
{
if (W1 == null)
{
W1 = new Window1();
W1.Hoofdmenu = this;
W1.checkLang();
W1.Show();
}
else
{
W1.checkLang();
W1.Visibility = Visibility.Visible;
}
this.Visibility = Visibility.Hidden;
}
On window 1 there is a Back button, that has this snip-it of code in it (Where "Hoofdmenu" us the main window):
Hoofdmenu.updateStatistics();
Hoofdmenu.Visibility = Visibility.Visible;
this.Visibility = Visibility.Hidden;
But again, this time when standing in the main window (so window 1 is hidden) i want to close down that window 1. but using W1.Close() does not seem to work. So i am looking for a way to Close that window 1, not change its visibility.
EDIT 2 - Solution
So using W1.Close(); did not work, although a small change this.W1.Close(); did work in fact :)
You can create object of Form2 in window and intialize its visiblity to false.
On click of button you can simpliy say
public partial class MainWindow : Window
{
private Window1 window2;
public MainWindow()
{
InitializeComponent();
this.window2 = new Window1();
this.window2.Show();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.window2.Visibility = System.Windows.Visibility.Hidden;
}
}
to make it visible again
after reading your code, thats not possible the way you want it. the window1 instance is local object. so you cant reach it out side if this method.
the best was is to have a close button on window1 with this.close()
or you create a global instance in your main window and then check if not null then close it.
Can anyone here do me a favor?
I have a MainWindow with a HideButton and RetrieveButton. When I click on either one button, it will goes to another ChildWindow. My ChildWindow have a OKButton.
The question here,
How to set if else statement in C# for pseudocode below?
private void OKButton_Click(object sender, EventArgs e)
{
// pseudocode
if (HideButton in MainWindow is clicked)
{
// Perform the works
}
if(RetrieveButton in MainWindow is clicked)
{
// Perform other works
}
Thanks in advance.
By, Aeris
If you are creating the child window on Retrieve or Hide you can easily pass parameters then either via the constructor or by setting a custom property:
ChildWindow child = new ChildWindow();
child.Retrieving = true;
child.Show();