Read input from popup window before executing entire main constructor - c#

I have a wpf application in which I have two wpf windows. One is the main GUI and another is a popup which asks the user to input a number into a text box then press a button.
What I'm wondering is can I somehow call the popup window to be displayed in the main window constructor (this much I have with popup.Show()) and then read the input and wait until the user presses the button to continue on with the rest of the code in the constructor?
Basically once it gets to the popup.Show() line I want it to wait for the user to enter a value and press the button before the rest of the code after popup.Show() in the main window constructor is executed.

Using ShowDialog() instead of Show() will cause the execution to pause until the popup is closed.

Use this:
popup.ShowDialog(); // Execution will halt here until the 'popup' is closed
I personally avoid using custom code inside window constuctor, I usually put this code on Window_Loaded

This should do the trick, but it will not show MainWindow until the Popup is closed.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnInitialized(EventArgs e)
{
var popup = new PopupWindow();
popup.ShowDialog();
base.OnInitialized(e);
}
}
For the Popup
public partial class PopupWindow : Window
{
public PopupWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Close();
}
}

Related

How to propagate the StateChanged event

I have a child window that has to be on top of another one which is the main.
I don't want to put the child one as TopMost since the user might want to check for data on other windows.
In short the child has to follow that maximize/minimize events as the parent main one
Main minimize--->Child minimize
Main maximize--->Child maximize
To do that I have defined in the main:
this.StateChanged += MainWindow_StateChanged;
and in that
public static event EventHandler OnMainWindowStateChanged;
private void MainWindow_StateChanged(object sender, EventArgs e)
{
OnMainWindowStateChanged?.Invoke(sender,e);
}
The logic should be:
Main window main class ---> Main window engine class ----> child window
To put some names it:
public MainWindow()
{
this.StateChanged += MainWindow_StateChanged;
//call to the engine
m_Designer = new CWorkFlowEditor(this, App.IsDeployment, OnMainWindowStateChanged);
}
...
//In the engine:
public EventHandler OnMainWindowStateChanged;
public CWorkFlowEditor(object parent, bool IsDeployment, EventHandler _OnMainWindowStateChanged)
{
OnMainWindowStateChanged = _OnMainWindowStateChanged;
}
...
// Finally, when I want to create the final child window:
wndPluginConfigurator = new Window() {};
OnMainWindowStateChanged += MainWindow_StateChanged;
wndPluginConfigurator.ShowDialog();
}
private void MainWindow_StateChanged(object sender, EventArgs e)
{
Console.Beep();
}
So the fact is that this event is never called for the above OnMainWindowStateChanged event is always null. And that is for the OnMainWindowStateChanged is also always null.
Obviously if there is a better way to achieve the result and I'd be most grateful for the explanation
Thanks for helping
ADD: The MainWindow is not visible to the CWorkflowEditor. I have therefore tried to pass the EventHAndler with an interface but that didn't work either.
To achieve the following
Main minimize--->Child minimize
Main maximize--->Child maximize
While launching the Child window set the Owner with Main Window.
Means
Window childwindow = new Window
childwindow.Owner = MainWindow
childwindow.Show()
There seems to be some issue passing your eventhandler around, but as the eventhandler is static surely it will be easier to do this instead:
MainWindow.OnMainWindowStateChanged += MainWindow_StateChanged;

C# Specific value passing between forms without new instance

I have a C# application that allows the user to log certain events that occur in a game. For simplicity I'll call them ParentForm and ChildForm.
ParentForm is used 99% of the time, to log common events. This is represented as the user clicking a PictureBox and the Tag property of that PictureBox being added to a ListBox. When a "rare" event occurs, the user can click a "log rare event" button on ParentForm to open ChildForm which opens a set of "rare event" PictureBoxes, which function the same as in the ParentForm. The challenge is that I want these common and rare events to be logged to the same ListBox, so I am trying to find out how I would get a PictureBox click (and subsequent Tag from this PictureBox) on the ChildForm to the ListBox on the ParentForm.
The ParentForm does not close while ChildForm is open, and needs to stay open.
In the ParentForm code, I already have the code needed to capture one of the PictureBox clicks and grabbing the Tag, as well as handling dealing with adding it to the ListBox, so it'd be nice if I could just use these.
Here's what I've tried so far for the Parent:
// This file is EventLogger.cs
using rareEvent;
namespace mainWindow {
public partial class EventLogger : Form {
// In the ParentForm (listeners for PictureBox clicks are handled elsewhere)
public void pictureBox_Click(object sender, EventArgs e) {
PictureBox pbSender = (PictureBox) sender;
// Open new window and handle "rare" drops
if (pbSender.Tag.ToString() == "rare") {
// Open rare form
EventLogger.RareForm rare = new EventLogger.RareForm();
rare.Show();
}
}
}
}
and here's the child:
// This file is Rare.cs
using EventLogger;
namespace rareEvent {
public partial class rareEventForm : Form {
// In the ChildForm
private void pictureBox_Click(object sender, EventArgs e) {
// Does not compile if form is not instantiated, but I do not
// want a new instance
EventLogger form;
form.pictureBox_Click(sender, e);
}
}
}
I figured something like this would work, but it gives the error
The type or namespace name 'EventLogger' does not exist in the namespace
'mainWindow' (are you missing an assembly reference?)
Any help would be much appreciated. All the other examples I've found of value passing between forms all seem to create new instances which I don't want or were 8 years old and didn't work.
Appreciate it!
Edit: Code updated to have using <namespace> in each file. The problem still exists of not being able to send values between both forms without using new. (See comment to this answer)
In the first form create an instance (of it) here like my form1. It must be static and all datatypes you want to access should be public.
//FORM1
public partial class Form1 : Form
{
//Instance of this form
public static Form1 instance;
//For testing
public string myProperty = "TEST";
//Assign instance to this either in the constructor on on load like this
public Form1()
{
InitializeComponent();
instance = this;
}
//or
private void Form1_Load(object sender, EventArgs e)
{
//Assign the instance to this class
instance = this;
}
Then in form2 when calling EventLogger.RareForm rare = new EventLogger.RareForm(); instead of new form do
EventLogger.RareForm rare = EventLogger.RareForm.instance
Or in my case
Form1 frm = Form1.instance;
I then check the property of form 1 FROM form2 like so
Console.WriteLine(frm.myProperty);
Output was "Test"
Any trouble shout.

Sending object to method in another class on event

In my second window, on double click I want to call a method in my MainWindow and send it an object.
Everything worked just fine when the second window was Owned by the MainWindow, but that caused MainWindow to always be drawn behind the second which is not what I wanted.
So my question is, how on earth do I call my public LoadSong(Song tempSong) method in my MainWindow on button click in my second window (assuming that I cannot directly call the method)?
There are many ways to skin this cat. Below two examples.
First Approach
Simple approach without any external libraries would be to create a custom even on the child window and subscribe to it from parent. Also you can propagate an object this way.
The object to propagate:
public class MyCommunicationObject
{
public string Message { get; set; }
}
And then the child window:
public partial class ChildWindow : Window
{
public event Action<MyCommunicationObject> MyChildWindowEvent;
public ChildWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var myObject = new MyCommunicationObject();
myObject.Message = "Hello from Child Window";
this.MyChildWindowEvent(myObject);
}
}
Clicking the button will propagate the MyChildWindowEvent event.
In the main window you have to subscribe for the event when you create the child dialog (in my example I'm doing that on button click because that's when the window is created).
The main window code:
private void Button_Click(object sender, RoutedEventArgs e)
{
var childWindow = new ChildWindow();
childWindow.MyChildWindowEvent += ChildWindow_MyChildWindowEvent;
childWindow.ShowDialog();
}
Second Approach
Or as suggested above use an EventAggregator. You can use for instance Prism. You will have to install it using NuGet manager. Once it's installed it Allows you to use EventAggregator object. The object can propagate events that inherit from PubSubEvent, e.g.:
public class MyEvent : PubSubEvent<MyCommunicationObject>
{
}
The main window and child window have to share an instance of the EventAggregator. Then you have to subscribe for an event that's propagated by your child window. Assuming the object has been created in the main window below is an example how to subscribe and handle the event on the main window (again on button click):
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var childWindow = new AnotherChildWindow(eventAggregator);
eventAggregator.GetEvent<MyEvent>().Subscribe(obj =>
{
this.myTextBox2.Text = obj.Message;
});
childWindow.ShowDialog();
}
And the child window has to publish the event (together with the object that's used for communication):
private void Button_Click(object sender, RoutedEventArgs e)
{
var myObject = new MyCommunicationObject();
myObject.Message = "Hello from another child window";
this.eventAggregator.GetEvent<MyEvent>().Publish(myObject);
}
Here on the child window the instance of the EventAggregator comes from the main window.
You can use EventAggregator or other event-based patterns.
First create new event with property of your object type to send it between components.
Next subscribe MainWindow to your event and call LoadSong in event handler with parameter received from handler parameter.
Finally raise (or publish in other terms) your event from your second window on double click event handler.
As you can see both of implementations is a part of MVVM libraries and this pattern can be useful for your app.

A Object of Window class in WPF project cannot be activated

I add a window class in my WPF project as below:
public partial class ParameterInput : Window
{
public ParameterInput()
{
InitializeComponent();
}
public void show()
{
bool ac= Activate();
}
}
And I do create a object of this class, and I hope it can be activated.
void myTap(object sender, MouseButtonEventArgs e)
{
ParameterInput ParameterInputDialog= new ParameterInput();
ParameterInputDialog.show();
//bool ac = ParameterInputDialog.Activate();
}
But I find this method do not work, the return value (ac) is false. why? Do anybody know how to solve this problem? I just want to open the dialog which I defined.
this is because in Windows Forms and in WPF as well, to show a Window you should call its Show method not just the Activate one, try to call the Show Method instead, see an example here:
How to open second window from first window in wpf?
This question has be solved, please see: https://msdn.microsoft.com/en-us/library/system.windows.window.owner%28v=vs.110%29.aspx.
So I change my code into:
ParameterInput ParameterInputDialog= new ParameterInput();
ParameterInputDialog.Owner = this;
ParameterInputDialog.Show();
And it do works well. Thanks for all your help.

passing data from a windows form to a xaml.cs file

I'm using WPF for creating my application, I am calling a windows form using formobject.Show()
from a xaml.cs file,
In the form I have Accept button and a cancel button . How to make the xaml.cs file know which button is clicked by the user in the form.? As the Execution(in ###.xaml.cs) depends on the button clicked.
I solved it, used the property
this.DialogResult = DialogResult.OK; in the the form
and used
if (confirm.DialogResult.ToString() == "OK") in the cs file to check which button is clicked
#Sebastian thanks for the idea.
Do you want to do pure Confirm / Cancel evaluation or do you want to evaluate a more complex result? For cancel / confirm, you can do as described here, using AcceptButton and CancelButton (those are for convenience only, to hook up Esc and Enter with the buttons) and the DialogResult property.
A more complex result is done just the same way, just that you don't set the DialogResult, but a custom property:
public partial class Form1 : Form
{
public string MyProperty { get; set; }
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MyProperty = "Some complex result";
}
private void button2_Click(object sender, EventArgs e)
{
MyProperty = "Some other complex result";
}
}
You can easily use myWinform.MyProperty to get the value in your XAML.cs file once the modal dialog is closed (the instance is not disposed, since your variable references it).

Categories

Resources