Tech Off Thread

2 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Help with "Improving perceived WPF app startup performance with MEF and a Splash Screen".

Back to Forum: Tech Off
  • User profile image
    VcDeveloper

    Hi,

    Need help trying to get my custom splash screen working based on this example from Channel 9 "Improving perceived WPF app startup performance with MEF and a Splash Screen".

    I can't get any of the Storyboards to work nor display text in a TextBlock, creating the splash screen during InitializeModules() in my MefBootstrapper:

    public class NatsarBootstrapper : MefBootstrapper
    {
        #region Private Properties
        private IEventAggregator EventAggregator
        {
            get { return ServiceLocator.Current.GetInstance<IEventAggregator>(); }
        }
        #endregion
    
        protected override void InitializeModules()
        {
            IModuleManager manager = ServiceLocator.Current.GetInstance<IModuleManager>();
    
            Loading loading = this.Container.GetExportedValue<Loading>();
            Shell shellMain = this.Container.GetExportedValue<Shell>();
    
            loading.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            loading.WindowState = WindowState.Normal;
    
            Application.Current.MainWindow = loading;
            Application.Current.MainWindow.Show();
    
            EventAggregator.GetEvent<MessageUpdateEvent>().Publish(new MessageUpdateEvent { Message = "Loading TurahStudyUIModule" });
            manager.LoadModule("TurahStudyUIModule");
    
            Application.Current.MainWindow.Hide();
    
            TurahStudyUIView view = ServiceLocator.Current.GetInstance<TurahStudyUIView>();
    
            shellMain.Height = 768;
            shellMain.Width = 1024;
            shellMain.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            shellMain.WindowState = WindowState.Maximized;
            shellMain.Activate();
    
            Application.Current.MainWindow = shellMain;
            Application.Current.MainWindow.Content = view;
            Application.Current.MainWindow.Show();
        }
    
        protected override void ConfigureAggregateCatalog()
        {
            try
            {
                this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(NatsarBootstrapper).Assembly));
                this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(NatsarCommonModule).Assembly));
                this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(TurahStudyUIModule).Assembly));
            }
            catch (Exception msg)
            {
                .....
            }
        }
    
        protected override DependencyObject CreateShell()
        {
            DependencyObject shell = null;
    
            return shell;
        }
    }

    Loading.xaml Window:

    <Window 
        x:Class="NatsarTurahStudyMaster.Views.Loading"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        AllowsTransparency="True" WindowStyle="None" >
        <Window.Background>
            <ImageBrush ImageSource="habakkuk-paleo-hebrew.png"  Stretch="UniformToFill"/>
        </Window.Background>
        <Window.Resources>
            <Storyboard  x:Key="InTransition">
    
                    <!-- Create an animation that repeats indefinitely. -->
                    <DoubleAnimation 
                      Storyboard.TargetName="foreverRepeatingRectangle" Storyboard.TargetProperty="(Rectangle.Width)" 
                      From="50" To="300" Duration="0:0:2" RepeatBehavior="Forever" />
    
                    <!-- Create an animation that repeats for four seconds. As a result, the
                         animation repeats twice. -->
                    <DoubleAnimation Storyboard.TargetName="fourSecondsRepeatingRectangle" Storyboard.TargetProperty="(Rectangle.Width)"
                      From="50" To="300" Duration="0:0:2" RepeatBehavior="0:0:4" />
    
                    <!-- Create an animation that repeats twice. -->
                    <DoubleAnimation Storyboard.TargetName="twiceRepeatingRectangle" Storyboard.TargetProperty="(Rectangle.Width)" 
                      From="50" To="300" Duration="0:0:2" RepeatBehavior="2x" />
    
                    <!-- Create an animation that repeats 0.5 times. The resulting animation
                         plays for one second, half of its Duration. It animates from 50 to 150. -->
                    <DoubleAnimation Storyboard.TargetName="halfRepeatingRectangle" Storyboard.TargetProperty="(Rectangle.Width)" 
                      From="50" To="300" Duration="0:0:2" RepeatBehavior="0.5x" />
    
                    <!-- Create an animation that repeats for one second. The resulting animation
                         plays for one second, half of its Duration. It animates from 50 to 150. -->
                    <DoubleAnimation Storyboard.TargetName="oneSecondRepeatingRectangle" Storyboard.TargetProperty="(Rectangle.Width)" 
                      From="50" To="300" Duration="0:0:2" RepeatBehavior="0:0:1" />
                </Storyboard>
        </Window.Resources>
    
        <Window.Triggers>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                <BeginStoryboard Storyboard="{StaticResource InTransition}"/>
            </EventTrigger>
        </Window.Triggers>
        <Grid>
            <Border HorizontalAlignment="Stretch">
                <StackPanel Margin="20" >
                    <TextBlock>RepeatBehavior="Forever"</TextBlock>
                    <Rectangle Name="foreverRepeatingRectangle" Fill="#AA3333FF" Width="50" Height="20" HorizontalAlignment="Left" />
                    <TextBlock Margin="0,20,0,0">RepeatBehavior="0:0:4"</TextBlock>
                    <Rectangle Name="fourSecondsRepeatingRectangle" Fill="#AA3333FF" Width="50" Height="20" HorizontalAlignment="Left" />
                    <TextBlock Margin="0,20,0,0">RepeatBehavior="2x"</TextBlock>
                    <Rectangle Name="twiceRepeatingRectangle" Fill="#AA3333FF" Width="50" Height="20" HorizontalAlignment="Left" />
                    <TextBlock Margin="0,20,0,0">RepeatBehavior="0.5x"</TextBlock>
                    <Rectangle Name="halfRepeatingRectangle" Fill="#AA3333FF" Width="50" Height="20" HorizontalAlignment="Left" />
                    <TextBlock Margin="0,20,0,0">RepeatBehavior="0:0:1"</TextBlock>
                    <Rectangle Name="oneSecondRepeatingRectangle" Fill="#AA3333FF" Width="50" Height="20" HorizontalAlignment="Left" />
                </StackPanel>
            </Border>
    
            <TextBlock Text="{Binding Status}" Margin="10,0" Grid.Row="2" Grid.ColumnSpan="2" 
                       TextAlignment="Right">
                <TextBlock.Effect>
                    <DropShadowEffect ShadowDepth="1" Color="#99ffffff"/>
                </TextBlock.Effect>
            </TextBlock>
        </Grid>
    </Window>
    

    Loading.xaml.cs:

    [Export(typeof(Loading))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public partial class Loading : Window, IPartImportsSatisfiedNotification
    {
        public Loading()
        {
            InitializeComponent();
        }
    
        [Import]
        public LoadingModel ViewModel
        {
            set
            {
                this.DataContext = value;
            }
            get
            {
                return DataContext as LoadingModel;
            }
        }
    
        /// <summary>
        /// Called when a part's imports have been satisfied and it is safe to use.
        /// </summary>
        public void OnImportsSatisfied()
        {
            // IPartImportsSatisfiedNotification is useful when you want to coordinate doing some work
            // with imported parts independent of when the UI is visible.
            Debug.WriteLine("Loading OnImportsSatisfied instantiation");
        }
    }
    

    LoadingModel.cs is where I'm just sending test text:

    [Export(typeof(LoadingModel))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class LoadingModel : NotificationObject
    {
        [ImportingConstructor]
        public LoadingModel(IEventAggregator eventAggregator)
        {
            Debug.WriteLine("LoadingModel instantiation");
            eventAggregator.GetEvent<MessageUpdateEvent>().Subscribe(e => UpdateMessage(e.Message));
        }
    
        private string _status;
        public string Status
        {
            get { return _status; }
            set
            { 
                _status = value; 
                RaisePropertyChanged(() => this.Status); 
            }
        }
    
        private void UpdateMessage(string message)
        {
            if (string.IsNullOrEmpty(message))
            {
                return;
            }
    
            int maxRecords = 1000;
            for (int x = 1; x < maxRecords; x++)
            {
                System.Threading.Thread.Sleep(10);
                Status = string.Format("{0}: {1} {2}",message ,Convert.ToInt32( ((decimal)x / (decimal)maxRecords) * 100), "...");
            }
        }
    }

    But, nothing is working?

  • User profile image
    VcDeveloper

    Well, I couldn't get it to work as I wanted, so I had to result to doing it this way:

    protected override void InitializeModules()
    {
        Shell shellMain = this.Container.GetExportedValue<Shell>();
    
        shellMain.InitializeMainWindow();
    
        TurahStudyUIView view = ServiceLocator.Current.GetInstance<TurahStudyUIView>();
    
        shellMain.Height = 768;
        shellMain.Width = 1024;
        shellMain.WindowStartupLocation = WindowStartupLocation.CenterScreen;
        shellMain.WindowState = WindowState.Maximized;
        shellMain.Activate();
    
        Application.Current.MainWindow = shellMain;
        Application.Current.MainWindow.Content = view;
        Application.Current.MainWindow.Activate();
    }
    

    and put the splash screen in my main window Shell.xaml.cs:

    [Export(typeof(Shell))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public partial class Shell : Window, IPartImportsSatisfiedNotification
    {
        private readonly BackgroundWorker _compositionBackgroundWorker = new BackgroundWorker();
        Loading loading;
    
        public Shell()
        {
            InitializeComponent();
    
            _compositionBackgroundWorker.DoWork += CompositionBackgroundWorker_DoWork;
            _compositionBackgroundWorker.RunWorkerCompleted += CompositionBackgroundWorkerRunWorker_Completed;
        }
    
        public void InitializeMainWindow()
        {
            // Set the Window.Content to the "Loading UI" UserControl
            loading = ServiceLocator.Current.GetInstance<Loading>();
            loading.Show();
    
            _compositionBackgroundWorker.RunWorkerAsync();
        }
    
        private void CompositionBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            this.InitializeModules();
        }
    
        private void InitializeModules()
        {
            IModuleManager manager = ServiceLocator.Current.GetInstance<IModuleManager>();
    
            int maxRecords = 1000;
            for (int x = 1; x < maxRecords; x++)
            {
                System.Threading.Thread.Sleep(5);
                System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => { loading.ViewModel.Status = string.Format("{0}: {1} {2}", "Loading", Convert.ToInt32(((decimal)x / (decimal)maxRecords) * 100), "..."); }));
            }
        }
    
        private void CompositionBackgroundWorkerRunWorker_Completed(object sender, RunWorkerCompletedEventArgs e)
        {
            loading.Hide();
            loading.Close();
            this.Show();
        }
    
        [Import]
        public ShellModel ViewModel
        {
            set
            {
                this.DataContext = value;
            }
            get
            {
                return DataContext as ShellModel;
            }
        }
    
        /// <summary>
        /// Called when a part's imports have been satisfied and it is safe to use.
        /// </summary>
        public void OnImportsSatisfied()
        {
            // IPartImportsSatisfiedNotification is useful when you want to coordinate doing some work
            // with imported parts independent of when the UI is visible.
            Debug.WriteLine("Shell OnImportsSatisfied instantiation");
        }
    }
    

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.