locked
Calling other forms from the ViewModel RRS feed

  • Question

  • I have a splash screen that runs, calls a login screen if needed, and then starts the main window.  I'm new wpf and mvvm and i'm trying to learn the right way the first time.  This is what I've come up with, but it feels....dirty.  Any suggestion would be greatly appreciated.

    protected override void OnStartup(StartupEventArgs e)
            {
                base.OnStartup(e);
    
                SplashViewModel vmSplash = new SplashViewModel();
                winSplash wSplash = new winSplash();
                wSplash.DataContext = vmSplash;
    
                //The application initialization completed successfully so lets run the main window
                vmSplash.OnSplashComplete += (sender, args) =>
                {
                    wSplash.Close();
                    winMain wMain = new winMain();
                    wMain.ShowDialog();
                    
                };
    
                //The application initialization needs login information
                vmSplash.OnLogInNeeded += (sender, args) =>
                {
                    winLogIn wLogIn = new winLogIn();
                    wLogIn.ShowDialog();                
                };
    
                //The application initalizaion did not complete
                vmSplash.OnSplashIncomplete += (sender, args) =>
                {
                    Application.Current.Shutdown();
                };
    
                //Show the splash screen
                wSplash.ShowDialog();
    
                Application.Current.Shutdown();
            }
    
     public class SplashViewModel : MVVM.ViewModelBase, IClosable
        {
            /// <summary>
            /// Primary thread.  Everything is ran from here.
            /// </summary>        
            BackgroundWorker bgwInitialize = new BackgroundWorker();
    
            public event EventHandler<EventArgs> OnSplashComplete = null;
    
            public event EventHandler<EventArgs> OnSplashIncomplete = null;
    
            public event EventHandler<EventArgs> OnLogInNeeded = null;
    }


    • Edited by JBHowl Wednesday, April 27, 2016 3:12 PM
    Wednesday, April 27, 2016 3:11 PM

Answers

  • Unless you really are going to substitute a different viewmodel each time then I strongly advise against instantiating viewmodel and view separately.

    I've worked on something that did that and you're asking for memory leaks.

    The simple way is to make a viewmodel a private member of a view and make the view instantiate it in xaml.

    eg

    <Window ...
        >
        <Window.DataContext>
            <local:MainWindowViewModel/>
        </Window.DataContext>

    You also get intellisense support as you bind to properties of your viewmodel.

    .

    In wpf there's a mechanism for splash screens. These are pictures. You add a picture and set it's Build Action to SplashScreen in Properties.

    This will, of course, do nothing other than show your picture.

    If you really need interaction in the splash screen then that's your main window because it's the first window you're going to show.

    Personally.

    I would make the login a usercontrol and host it in your mainwindow rather than showing another window.

    This is a very simplified version of that sort of approach:

    https://gallery.technet.microsoft.com/wpf-Simple-Navigation-With-2c3342a4

    Unless you really need multiple windows for some reason, make your app a single window app.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:21 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:16 PM
    Wednesday, April 27, 2016 3:30 PM
  • >>This is what I've come up with, but it feels....dirty.

    Your OnStartup code doesn't look bad. You display the splash screen the first thing you do and set its DataContext to an instance of a view model. I guess the SplashViewModel is then responsible for initializing the application and raise the appropriate event which you then handle. You could consider encapsulating the logic of displaying the splash screen and the other windows in a Bootstrapper class. Also there is no need to call the Application.Current.Shutdown() method when the ShowDialog() method of the SplashScreen has returned. You may also want to set the ShutdownMode property as appropriate, e.g.:

    protected override void OnStartup(StartupEventArgs e)
            {
                base.OnStartup(e);
    
                Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
                SplashViewModel vmSplash = new SplashViewModel();
                winSplash wSplash = new winSplash();
                wSplash.DataContext = vmSplash;
    
                //Show the splash screen
                wSplash.ShowDialog();
    
         //handle your event(s):
                Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
                MainWindow mw = new WpfApplication6.MainWindow();
                Application.Current.MainWindow = mw;
                mw.Show();
            }
    

    When it comes to the initialization of the view models, there is nothing wrong with creating the view models before you create the views. This is very common and far wider used and more flexible approach than setting the DataContext property of a view in its XAML markup.


    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:21 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:16 PM
    Wednesday, April 27, 2016 7:37 PM

All replies

  • Unless you really are going to substitute a different viewmodel each time then I strongly advise against instantiating viewmodel and view separately.

    I've worked on something that did that and you're asking for memory leaks.

    The simple way is to make a viewmodel a private member of a view and make the view instantiate it in xaml.

    eg

    <Window ...
        >
        <Window.DataContext>
            <local:MainWindowViewModel/>
        </Window.DataContext>

    You also get intellisense support as you bind to properties of your viewmodel.

    .

    In wpf there's a mechanism for splash screens. These are pictures. You add a picture and set it's Build Action to SplashScreen in Properties.

    This will, of course, do nothing other than show your picture.

    If you really need interaction in the splash screen then that's your main window because it's the first window you're going to show.

    Personally.

    I would make the login a usercontrol and host it in your mainwindow rather than showing another window.

    This is a very simplified version of that sort of approach:

    https://gallery.technet.microsoft.com/wpf-Simple-Navigation-With-2c3342a4

    Unless you really need multiple windows for some reason, make your app a single window app.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:21 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:16 PM
    Wednesday, April 27, 2016 3:30 PM
  • >>This is what I've come up with, but it feels....dirty.

    Your OnStartup code doesn't look bad. You display the splash screen the first thing you do and set its DataContext to an instance of a view model. I guess the SplashViewModel is then responsible for initializing the application and raise the appropriate event which you then handle. You could consider encapsulating the logic of displaying the splash screen and the other windows in a Bootstrapper class. Also there is no need to call the Application.Current.Shutdown() method when the ShowDialog() method of the SplashScreen has returned. You may also want to set the ShutdownMode property as appropriate, e.g.:

    protected override void OnStartup(StartupEventArgs e)
            {
                base.OnStartup(e);
    
                Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
                SplashViewModel vmSplash = new SplashViewModel();
                winSplash wSplash = new winSplash();
                wSplash.DataContext = vmSplash;
    
                //Show the splash screen
                wSplash.ShowDialog();
    
         //handle your event(s):
                Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
                MainWindow mw = new WpfApplication6.MainWindow();
                Application.Current.MainWindow = mw;
                mw.Show();
            }
    

    When it comes to the initialization of the view models, there is nothing wrong with creating the view models before you create the views. This is very common and far wider used and more flexible approach than setting the DataContext property of a view in its XAML markup.


    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:21 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:16 PM
    Wednesday, April 27, 2016 7:37 PM