Search code examples
c#winformsaxwindowsmediaplayer

Switching between Window Forms does not seem to work


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.


Solution

  • 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.