I'm building a GUI application with C# and gtk#. I've encountered an issue recently and was looking for the best solution to this problem:
I have a modal window that pops up for the user to enter a number. This window is a separate window accessed from my main window and it's set up like this:
public class MainWindow()
{
public NumberEntry numEntry;
Whenever I need numerical input from the user, I call ShowAll() on the public Window property of NumberEntry like:
numEntry.win.ShowAll();
And all of this works fine. Afterwards, to get the value they entered, I call:
int entered = numEntry.valueEntered;
The issue is obviously that code continues executing immediately after the ShowAll() line is finished, and numEntry.valueEntered is always 0. What I'd like to do (and have been trying to do), is to suspend the main thread, and open up the number entry window in a second thread, and join back to the main thread when this is complete. Suspending the main thread seems to prevent GUI changes making the program freeze when I try to open the number entry window. I'd also like to avoid callback methods if at all possible, seeing as how this would get rather complicated after awhile. Any advice? Thanks!
Seems like when GTK window is closed all its child controls are cleared. So to get the result from the custom dialog window you may do the following (I am not gtk guru but its works for me):
1. Create a new dialog window with your controls (I used Xamarin studio). Add result properties, OK and Cancel handlers and override OnDeleteEvent method:
public partial class MyDialog : Gtk.Dialog
{
public string Results {
get;
private set;
}
public MyDialog ()
{
this.Build ();
}
protected override bool OnDeleteEvent (Gdk.Event evnt)
{
Results = entry2.Text; // if user pressed on X button..
return base.OnDeleteEvent (evnt);
}
protected void OnButtonOkClicked (object sender, EventArgs e)
{
Results = entry2.Text;
Destroy ();
}
protected void OnButtonCancelClicked (object sender, EventArgs e)
{
Results = string.Empty;
Destroy ();
}
}
2. In your main window create a dialog object and attach to its Destroyed event your event handler:
protected void OnButtonClicked (object sender, EventArgs e)
{
var dialog = new MyDialog ();
dialog.Destroyed += HandleClose;
}
3. Get the results when dialog is closed:
void HandleClose (object sender, EventArgs e)
{
var dialog = sender as MyDialog;
var textResult = dialog.Results;
}
If you whant you also may specify a dialog result property and etс.
Related
Hey there StackOverflow community!
So I've been working on an application that checks if the user has entered valid credentials in a Login() form, then it switches over to an Intro_Sequence() form (where a .mp4 file is played in fullscreen mode) as a sort of aesthetic addition to the app. So far so good, no problems whatsoever.
The problem comes right after the Intro ends, where supposedly the application should switch over to a third form, called Main().
I have implemented a check whenever Windows Media Player (aka axWMPLib) changes its PlayState to see whether it has finished the playback.
If it has, then the Hide() event is called to conceal the current Form's window, then main.ShowDialog() should open the third form.
Afterwards, I call the Close() event to close the previous Form's window entirely.
Here is the code so far:
public partial class Intro_Sequence : Form
{
public static string Username;
public Intro_Sequence(string username)
{
InitializeComponent();
Username = username;
FormBorderStyle = FormBorderStyle.None;
Bounds = Screen.PrimaryScreen.Bounds;
TopMost = true;
intro.uiMode = "none";
intro.URL = AppDomain.CurrentDomain.BaseDirectory + "\\Intro.mp4";
intro.enableContextMenu = false;
DisableMouseClicks();
}
private void DisableMouseClicks()
{
if (this.Filter == null)
{
this.Filter = new MouseClickMessageFilter();
Application.AddMessageFilter(this.Filter);
}
}
private MouseClickMessageFilter Filter;
private const int LButtonDown = 0x201;
private const int LButtonUp = 0x202;
private const int LButtonDoubleClick = 0x203;
public class MouseClickMessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref System.Windows.Forms.Message m)
{
switch (m.Msg)
{
case LButtonDown:
case LButtonUp:
case LButtonDoubleClick:
return true;
}
return false;
}
}
private void Intro_Sequence_Load(object sender, EventArgs e)
{
}
private void intro_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if(intro.playState == WMPLib.WMPPlayState.wmppsMediaEnded)
{
Main main = new Main(Username);
this.Hide();
main.ShowDialog();
this.Close();
}
}
}
As you can see I have also added a filter to block clicks during playback, so as not to allow the user to pause it.
However, when I execute this code, it works perfectly fine until it finishes the video and then closes abruptly.
I tried putting breakpoints and everything seems to be fine.
It does call everything I tell it to call, yet the form doesn't even appear.
I have also tried several other alternatives, like not closing the Form at all, calling Show() instead of ShowDialog() and even not Hiding it at all.
It is as if it either freezes there or closes instantly without any sign of the Main form showing.
I also tried calling the Main() form from the Login() and it works perfectly from there.
I really don't know what is going on.
Any help would be appreciated.
How about something like this?
There are three forms. There's a Login form (in this case, it's just an empty form - you close it by clicking on the red X). It is popped up modally from within the Main form (while the main form is hidden).
There's a Splash screen on which your video is to play. I fake out the video by using await Task.Delay(4000); to get a pause. After the 4 second delay, I raise an event (equivalent to your media player event). What I do is show this modally from the main form. I put the event handler in this form; when the event is raised, I close the splash screen modal. The entire (non-designer) code for that form looks like (and, since there are no controls on this form, the designer code is pretty lean):
public partial class SplashScreen : Form
{
public event EventHandler SplashFinished;
public SplashScreen()
{
InitializeComponent();
this.SplashFinished += SplashScreen_SplashFinished;
}
private async void SplashScreen_Load(object sender, EventArgs e)
{
await Task.Delay(4000);
SplashFinished?.Invoke(this, new EventArgs());
}
private void SplashScreen_SplashFinished(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
}
Then there's the Main form. It gets fired up in the normal way from Program.cs:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
The only thing that I added to that form (from the out-of-the-box code) is:
private void Form1_Load(object sender, EventArgs e)
{
this.Hide();
var login = new LoginForm();
//should really check this, but for now
login.ShowDialog(this);
var splash = new SplashScreen();
splash.ShowDialog(this);
this.Show();
}
So, when the app starts, the user is shown the login form (the main form is hidden). He does what is needed to do (and the result is checked in the main form's Form1_Load handler.
If everything is cool, a new SplashScreen form is created and shown modally. When it pops up, the video starts (in this case, the video is simply an asynchronous timer). When the video ends, the SplashScreen handles the finished event, and uses it to close itself.
Once control returns to the main form, it displays itself.
I'm trying to do what is described in this post, display a log in window and when user successfully logs in, close it and open the main window of the application.
If the user logs on successfully, then I want to show the main window, if not, I want to exit the application
but the provided answers (at the time of posting this question) do not work for me since my code to show the windows is running from the App.cs.
I know the reason, its because the first window that starts up is automatically set to be the MainWindow of the application and when I call Close() on it, it exits the application. So the second window doesn't have a chance to open.
My question is how to overcome this? Or is this just not possible the way I described?
public partial class App : Application
{
public App(){}
private void Application_Startup(object sender, StartupEventArgs e)
{
LoginScreen f = new LoginScreen(); //becomes automatically set to application MainWindow
var result = f.ShowDialog(); //View contains a call to Close()
if (result == true) //at this point the LoginScreen is closed
{
MainWindow main = new MainWindow();
App.Current.MainWindow = main;
main.Show(); //no chance to show this, application exits
}
}
}
You can change application shutdown mode to OnExplicitShutdown and then call Application.Shutdown(0) whenever you want to. For example:
public App()
{
App.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (MessageBox.Show("Continue?", "", MessageBoxButton.YesNo) == MessageBoxResult.No)
App.Current.Shutdown(0);
}
Here in the constructor I'm changing application shudown mode and calling Shutdown method if I need to.
Caution: When you change ShutdownMode make sure to call Shutdown method otherwise your application will be in memory even after main window closes. I've overrided OnClosed method in my MainWindow to do that:
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
App.Current.Shutdown(0);
}
App.xaml : (In this file set the start window with the login view)
StartupUri="LoginWindow.xaml"
LoginWindow.xaml : (A file with a login window view)
LoginWindow.xaml.cs : (Code Behind for the view. Place here the function assigned to login. )
private void Login_Click(object sender, RoutedEventArgs e)
{
//Access control. If correct, go ahead. Here you must create a condition check
MainWindow main = new MainWindow();
main.Show();
this.Close();
}
Hi I'm relatively new to C# and completely new to windows form and basically trying to create a subliminal messaging program that at timed intervals will quickly display a message for it to then be hidden again.
I've managed to by looking through various other posts created another form that will pop up and then hide very quickly using
msgObject.Activate();
that brings the form to the front. However it is stopping me from being able to type when I'm working and I basically wanting to know if it is possible to make some kind of message or form appear at the front of all my other programs without it interrupting my current work or opening or closing of other windows and tasks if that makes sense. As currently it brings the form to the front of everything but will also stop me from being able to type etc.
I'm not sure if this is possible with my current method of using a form but if there is a way of achieving the result I'm after I'd be very grateful to find out
Thanks.
Here is more of my code to clarify
public partial class FormHomePage : Form
{
private bool startSubliminal = false;
msg msgObject = new msg();
List<string> subliminalMessages = new List<string>();
public FormHomePage()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
if (startSubliminal)
{
msgObject.Show();
msgObject.BringToFront();
msgObject.Activate();
}
}
private void button1_Click(object sender, EventArgs e)
{
subliminalMessages.Add(txtBox1.Text);
msgObject.LabelText = txtBox1.Text;
txtBox1.Text = string.Empty;
startSubliminal = true;
msgObject.Show();
msgObject.BringToFront();
}
private void timer2_Tick(object sender, EventArgs e)
{
msgObject.Hide();
}
}
How are you showing the second form (the message form) in the first place? You're probably using .Show() (right?), which will make the form "steal" the focus anyway. The same applies to .Activate() and .BringToFront().
Instead, what you can do is to show the message form and make sure it stays on top the current form, and then activate the current/main form once again.
Something like this should work:
var frm = new YourMsgForm();
frm.Show(this);
this.Activate();
Here's a demonstration:
Note that I used .Show(this) instead of .Show(), that's in order to set the current form as the Owner of the new one, that way we guarantee that the new form will stay on top of the current one. This is equivalent to calling frm.Owner = this; then frm.Show();.
Another way to make sure the form stays on top is by setting the TopMost property instead of the Owner property. However, doing so will make the new form on top of the other windows as well (not just your application).
I want to have a return value from my WPF window without close it.
I have an DLL with WPF usercontrol inside, I call it from my DLL code.
I have to call it, it returns me datas, then I send it datas.
But I don't want to create two different instance of the same window.
My code :
MP.UserControl1 a = new MP.UserControl1();
a.ShowDialog();
if (a.DialogResult.HasValue && a.DialogResult.Value == true)
{
a.Hide();
InitialDatas = a.inputData;
}
else
return 0;
Then I elaborate InitialDatas
And now I want to call a method inside my "a", and show it again, without create a new window.
Code :
a.SetValue(result, off1, InitialDatas);
a.ShowDialog();
I got error message : Cannot set visibility or call Show, ShowDialog or EnsureHandle after a window has been closed
Is it possible to solve?
I would solve this with an event model. You could do the following:
Create an event in the Form
Create an event handler in the caller
Subscribe to the event and do your logic
The called form:
namespace MyApplication
{
public delegate void MyEventHandler(object source, EventArgs e);
public class MyForm : Form
{
public event MyEventHandler OnInitialData;
private void btnOk_Click(object sender, EventArgs e)
{
OnInitialData?.Invoke(this, null);
}
}
}
In your other Form:
MP.UserControl1 a = new MP.UserControl1();
a.OnInitialData += UCA_OnInitialData;
private void UCA_OnInitialData(object sender, EventArgs e)
{
MP.UserControl1 a = sender as MP.UserControl1;
a.SetValue(result, off1, a.inputData);
}
a.ShowDialog();
As the error message states, you cannot close the window and then open it again.
Instead of closing a window you could hide it by calling the Hide() method and then showing it again by calling the Show() method.
But since the ShowDialog() method doesn't return until the window has been closed, this won't work for a dialog window though. If you require a modal window, you will have to create a new instance of the window and open this one. This shouldn't really be an issue though.
So I guess the answer to your question is simply no. You cannot re-open a closed dialog window.
I am trying to write a simple form application with mono Gtk# but am already stuck in the beginning I create a Dialog form inherits from Gtk.Dialog. The dialog form for collection basic information and returning these information as an object to main window or trigger some event to main window so it can do what it suppose to do in this case bind the data a TreeView control (which is another story). These are what I have tried so far;
Dialog code
public partial class MyDialog : Gtk.Dialog
{
public MyDialog ()
{
this.Build ();
}
protected void OnButtonOkClicked (object sender, EventArgs e)
{
int portNumber = 0;
iint.TryParse (spnPort.Text, out portNumber);
var myObj = new MyObj ();
myObj.Username = txtUsername.Text;
myObj.Password = txtPassport.Text;
// did not work as ParentWindow is a Gdk.Window
//(this.ParentWindow as MainWindow).AddObj(myObj);
//Also did not work because there is no response related method
//or property in the Dialog please read below code block this will make more sense
//this.OnResponse(myObj);
}
}
MainWindow Code to call dialo
protected void OnAddActionActivated (object sender, EventArgs e)
{
MyDialog s = new MyDialog();
s.Run();
s.Response += HandleResponse;
}
void HandleResponse (object o, ResponseArgs args)
{
//as this event has args.Args and args.RetVal I thought one would do what I wanted
//maybe I am using them all wrong
}
I appreciate it if some one can explain what is Gdk.Window is and what it is doing under Gtk control.
Just store the object you want to return in your dialog object, and provide access to it using a property. Don't forget to check whether the user pressed the cancel button (if you have one), conveniently by examining the return value of Run().
For an example see the sample code for the stock FileChooserDialog in the official documentation.