SplashWindow 여쭙습니다

안녕하세요 wpf에서 Splash Window 만들다가 머리가 깨질거같아 여쭙습니다.
WPF, Prism 사용해서 프로젝트 만들고 있는데 애플리케이션이 실행되기전에 Splash Window를 띄우고 사전 작업이 끝난 후에 메인윈도우를 띄우도록 구현하고 싶습니다.

internal class App : PrismApplication
  {
      protected override Window CreateShell()
      {
          return Container.Resolve<MainWindow>();
      }

      protected override void RegisterTypes(IContainerRegistry containerRegistry)
      {
          base.RegisterTypes(containerRegistry);
      }

      protected override void InitializeModules()
      {
          SplashWindow splashWindow = new SplashWindow();

          Task task = new Task(() =>
          {
              splashWindow.Dispatcher.BeginInvoke(() =>
              {
                  splashWindow.ShowDialog();
              });
          });

          task.Start();

          splashWindow.ChangeState(ConnectState.Fail);

          Task.Delay(3000).ContinueWith(_ =>
          {
              splashWindow.Dispatcher.Invoke(() => splashWindow.Close());
          }, TaskScheduler.FromCurrentSynchronizationContext());

          base.InitializeModules();
      }

코드를 이것저것 주워와서 넣다 보니 App.cs에 이렇게 코딩되어 있습니다. 현재는 3초뒤에 종료되게끔 해놓았습니다.
제가 구현하고자 하는 방법은 splashWindow가 떠있는 상태에서 어떤 상태를 변화시키는 사전 작업을 완료하고 Close()를 App.cs에서 호출해서 splashWindow가 꺼지면 MainWindow가 뜨게 하고 싶습니다. app.cs에서도 사전작업을 해야하는 코드가 진행되어야하고, splashWindow에서도 변화에 따라 UI가 변경되야해서 우선은 Task로 생성했는데 어떻게 하면 좋을까요…ㅠ

2개의 좋아요

하시고 싶으신 일이

  1. 스플래시 윈도우를 띄우고
  2. 어떠한 작업을 한 뒤
  3. 스플래시 윈도우를 끄는
    작업인가요??

그렇다면

  1. 지금은 모달로 띄우시는데, 모달리스로 스플래시 윈도우를 띄우고
  2. 어떠한 작업을 시행하고
  3. 모달리스로 띄운 스플래시 윈도우를 닫으면

되지 않을까요?

3개의 좋아요

넵 비슷하지만 스플래시 윈도우를 띄우고 끝나기 전까지 MainWindow가 오픈 안됐으면 합니다. app.cs에서 SplashWindow.Close() 됐을때 MainWindow가 오픈될수있게 하고싶습니다. ㅜ

2개의 좋아요

메인윈도우 Hide 상태로 띄우고 스플래쉬 닫을 때 Show하면 안 되나요?

2개의 좋아요

전 MainWindow를 교체하는 방식으로 사용합니다.
그리고 SplashWindow에서 어떠한 작업이 필요하다면 해당 뷰모델 생성자에서 처리하시면 될듯 합니다.

App.xaml.cs 에 OnStartup 함수에서 교체합니다.

protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            //스플래시 윈도우 띄움
            var splashWindow = new SplashWindow();
            this.MainWindow = splashWindow;
            this.MainWindow.Show();


            Task.Factory.StartNew(() =>
            {
                //잘 실행되는지 확인하기 위해 Delay
                System.Threading.Thread.Sleep(1000);

                this.Dispatcher.Invoke(() =>
                {
                    // 아래 new MainWindow를 호출하면서 MainViewModel이 실행되는데
                    // MainViewModel 생성자에서 초기화작업이 끝나면 MainWindow를 교체하면서 SplashWindow를 닫음.
                    var mainWindow = new MainWindow();
                    this.MainWindow = mainWindow;
                    mainWindow.Show();
                    splashWindow.Close();
                });
            });

        }

예제코드를 보니 헷갈릴수 있어 덧붙이자면 this.MainWindownew MainWindow()의 MainWindow는 다른 객체입니다.

3개의 좋아요

감사합니다. 뭔가 오기가 생겨서 해보고 있습니다…!

2개의 좋아요

감사합니다. 혹시 CreateShell에서 생성하는 윈도우는 어떻게 처리하셨나요??
뷰모델 없이 윈도우만 가지고 있게 만들어서 가져다 쓸 수 있게 하려고 합니다. 그래서 로직을 못 넣고 있습니다ㅜ.

2개의 좋아요

말씀해주신 방법으로 해결됐습니다 감사합니다!

2개의 좋아요

어떻게 처리하셨나요 ? 저는 진행하다보니 SplashWindow.Close() 처리를 하면 Main이 같이 Close 되고 있습니다,

1개의 좋아요

혹쉬 ShutdownMode 를 설정해보셨을까용?

1개의 좋아요

protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

        var splashScreen = new LoadingWindow();
        this.MainWindow = splashScreen;
        splashScreen.Show();

        Task.Factory.StartNew(() =>
        {
            for (int i = 1; i <= 100; i++)
            {
                System.Threading.Thread.Sleep(30);
                splashScreen.Dispatcher.InvokeAsync(() => splashScreen.ProgressBar.Value = i);
            }

            this.Dispatcher.Invoke(() =>
            {
                ShutdownMode = ShutdownMode.OnMainWindowClose;
                splashScreen.Close();
            });

            var mainWindow = Container.Resolve<MainWindow>();/*new MainWindow();*/
            this.MainWindow = mainWindow;
            mainWindow.Show();
        });
    }

이런 상태에요,

1개의 좋아요

저는 이렇게 해결했어요.

protected override Window CreateShell()
{
        return splashWindow;
}
protected override void InitializeModules()
{
        Task.Run(async () =>
        {
                await Task.Delay(1000);

                this.Dispatcher.Invoke(() =>
                {
                        this.MainWindow = new MyWindow();
                        this.MainWindow.Show();
                        splashWindow.Close();
                });
        });
            
        base.InitializeModules();
}
1개의 좋아요

protected override void InitializeModules()
{
Task.Run(async () =>
{
await Task.Delay(100);

            for (int i = 1; i <= 100; i++)
            {
                await Task.Delay(30);
                this.Dispatcher.Invoke(() =>
                {
                    SplashView.Progress = i;
                    SplashView.Rate = i.ToString() + "%";
                });
            }

            this.Dispatcher.Invoke(() => SplashView.Message = $"Load Complete !");
            await Task.Delay(500);

            this.Dispatcher.Invoke(() =>
            {
                this.MainWindow = Container.Resolve<MainWindow>();/*new MainWindow();*/
                this.MainWindow.Show();
                SplashView.Close();
            });
        }).ContinueWith(task =>
        {
            Console.WriteLine($"Load Complete !");

        }, TaskScheduler.FromCurrentSynchronizationContext());

        base.InitializeModules();
    }

저는 이렇게 처리하였는데, MainWindow 에서 ButtonClick Binding Command 로 MainPage를 바꿔주려고 하니 Display가 먹통이 되던데 혹시 이유를 아실까요 ?

Command Event도 정상적으로 들어오는데 Display Change가 안바뀌더라구요,

Command Event 함수는 이렇습니다.

    private void ExecuteNavigation(string key)
    {
        RegionManager.RequestNavigate(RegionName.MainWindow, key);
    }
1개의 좋아요

저도 비동기 함수쪽을 잘 몰라서 답변드리기 힘들거같습니다 ㅠㅠ

1개의 좋아요

ShutdownModeShutdownMode.OnMainWindowClose 로 설정하고 splashScreen.Close() 했으니 당연한 거 같은데요?

정확히 말하면 mainWindow 가 닫히는 게 아니라 프로세스가 종료되는 겁니다.

this.MainWindow = splashScreen;

한 상태에서

ShutdownMode = ShutdownMode.OnMainWindowClose;
splashScreen.Close();

했으니 splashScreen 이 Close 되면서 프로세스가 종료되는 거 같습니다.
splashScreen 종료와 프로세스 종료를 분리하고 싶다면 ShutdownMode 값을 바꿔서 해보는 게 어떤가 싶어요.

2개의 좋아요

App 개체 안에서 MainWIndow <=> SplashWindow 교체 과정에 생겼던 문제였습니다.

해당 조언으로 잘 해결되었습니다 ~!

2개의 좋아요