0
votes

So I'm trying to have a splash screen that has a progress bar that increments as my application loads. Obviously I've had to edit code to remove any IP, thankfully most of this is simple enough that none of it really matters. But any help would be greatly appreciated.

Failed Solution 1

Here is the code for my application block:

public class App : Application
{
   public void Run()
   {
      bool isLoaded = false;

      ProgressSplashScreen splashScreen = new ProgressSplashScreen(() => { isLoaded = true; });
      splashScreen.Show();
      SpinWait.SpinUntil(() => isLoaded);

      _bootStrapper = new BootStrapper(splashScreen);
      _bootStrapper.Run();

      splashScreen.Close();
    }
}

Here is the code for my splash screen XAML:

<Window x:Class="Application.ProgressSplashScreen"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Splash" BorderBrush="Transparent"
        AllowsTransparency="True" 
        Icon="../../Resources/Icons/Icon.ico"
        WindowStartupLocation="CenterScreen" 
        WindowStyle="None" Width="640" Height="520" 
        Background="Transparent" Name="SplashWindow" Topmost="True" >
   <Grid>
       <StackPanel Orientation="Vertical" VerticalAlignment="Stretch"
                   HorizontalAlignment="Stretch">
            <Image Source="../../Resources/Images/splash.jpg" Height="480" Width="640"/>
            <Grid>
               <ProgressBar Name="SplashProgress" Height="20" Minimum="0" Maximum="100"
                            BorderBrush="Transparent" />
               <Label Name="SplashMessage" VerticalAlignment="Bottom" 
                      HorizontalAlignment="Center"/>
            </Grid>
       </StackPanel>
    </Grid>
</Window>

And the Code Behind for the Splash Screen XAML:

using System;
using System.Threading;
using System.Windows;

namespace Application
{
    public partial class ProgressSplashScreen : Window
    {
        private SynchronizationContext _synchContext;

        public ProgressSplashScreen(Action isLoaded)
        {
            this.Loaded += (sender, args) => isLoaded();
            InitializeComponent();
            _synchContext = SynchronizationContext.Current;
        }

        public void SetProgress(double progress, string message)
        {
            _synchContext.Send((state) =>
            {
                SplashProgress.Value = progress;
                SplashMessage.Content = message;        
            }, null);        
        }
    }
}

And Finally the BootStrapper Class that I am trying to make the update calls from:

namespace Application
{
    internal sealed class BootStrapper : BaseMefBootstrapper
    {
        private ProgressSplashScreen _splash;

        public BootStrapper(ProgressSplashScreen splashScreen)
        {
            _splash = splashScreen;
        }

        public void Run()
        {
           // removed do stuff code here
           _splash.SetProgress(10, "Loading stuff...");
           // removed do stuff code here
           _splash.SetProgress(40, "Loading stuff...");
           // removed do stuff code here
           _splash.SetProgress(80, "Loading stuff...");
           // removed do stuff code here
           _splash.SetProgress(90, "Loading stuff...");
           // removed do stuff code here
           _splash.SetProgress(100, "Loading stuff...");
        }
    }
}

And so far my screen just sits there with an empty progress bar...

Failed Solution 2

ps... I've also tried

using System;
using System.Threading;
using System.Windows;

namespace Application
{
    public partial class ProgressSplashScreen : Window, INotifyPropertyChanged
    {
        private Dispatcher _dispatcher;
        public event PropertyChangedEventHandler PropertyChanged;
        private string _progressMessage;
        private double _progressValue;

        public string ProgressMessage
        {
            get { return _progressMessage; }
            set
            {
                _progressMessage = value;
                OnPropertyChanged("ProgressMessage");
             }
        }

        public double ProgressValue
        {
            get { return _progressValue; }
            set
            {
                _progressValue = value;
                OnPropertyChanged("ProgressValue");
            }
        }

        public ProgressSplashScreen(Action isLoaded)
        {
            this.Loaded += (sender, args) => isLoaded();
            InitializeComponent();
            _dispatcher = Dispatcher.CurrentDispatcher;
        }

        public void SetProgress(double progress, string message)
        {
            _dispatcher.BeginInvoke(new Action(() =>
            {
                ProgressValue = progress;
                ProgressMessage = message;
            }), DispatcherPriority.ContextIdle, null);       
        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

with this as the XAML

<Window x:Class="Application.ProgressSplashScreen"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Splash" BorderBrush="Transparent"
        AllowsTransparency="True" 
        Icon="../../Resources/Icons/Icon.ico"
        WindowStartupLocation="CenterScreen" 
        WindowStyle="None" Width="640" Height="520" 
        Background="Transparent" Name="SplashWindow" Topmost="True" >
   <Grid>
       <StackPanel Orientation="Vertical" VerticalAlignment="Stretch"
                   HorizontalAlignment="Stretch">
            <Image Source="../../Resources/Images/splash.jpg" Height="480" Width="640"/>
            <Grid>

               <ProgressBar Name="SplashProgress" Height="20" Minimum="0" Maximum="100" 
                            BorderBrush="Transparent" Value="{Binding ProgressValue, 
                            UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
            <Label Name="SplashMessage" VerticalAlignment="Bottom" HorizontalAlignment="Center" 
                   Content="{Binding ProgressMessage, 
                   UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
            </Grid>
       </StackPanel>
    </Grid>
</Window>

Any help would be great! Thanks! Really surprised this is as hard as it seems right now...

1
just wondering if you're setting isloaded = true to early and SpinUntil stops on true - kenny
Couldn't you run your stuff in a BackgroundWorker and set the value of the progress bar with ProgressChanged? - Bastien
@Kenny - Verified that isLoaded is getting hit correctly and that it is moving past it quickly. - James McDuffie
@Bastyen - I tried moving the entire progress dialog into a background worker and it showed up and then disappeared in like 2 seconds... not sure why it was disappearing from me. But I'll re-try that again today. - James McDuffie

1 Answers

0
votes

So what I was talking about is :

MainWindow.xaml

<Window x:Class="SplashSxreenExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Splashscreen" 
        WindowStyle="none" ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
        Height="400" Width="700" Background="#FF292929" FontFamily="Century Gothic"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">


    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/SplashScrTemplate.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="AUto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Content="Test Splash Screen" Foreground="LightGray" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="60"/>
        <Label Grid.Row="1" Content="{Binding ProgressMessage}" Foreground="LightGray" FontStyle="Italic"/>
        <ProgressBar Grid.Row="2" Height="3" Foreground="White" Style="{StaticResource FlatProgressBar}"
                     Value="{Binding ProgressValue}"/>

    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace SplashSxreenExample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged; 
        private string _progressMessage;
        private int _progressValue;
        private BackgroundWorker _mWorker;

        public MainWindow()
        {
            InitializeComponent();
            _mWorker = new BackgroundWorker();
            _mWorker.WorkerReportsProgress = true; //Allow reporting
            _mWorker.ProgressChanged += _mWorker_ProgressChanged;
            _mWorker.DoWork += _mWorker_DoWork;

            _mWorker.RunWorkerAsync();
        }

        void _mWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker wkr = sender as BackgroundWorker;

            wkr.ReportProgress(0, "Starting..."); //Reporting progress
            //Here do your stuff
            Thread.Sleep(500);
            wkr.ReportProgress(10, "Loading stuff...");
            //Here do your stuff
            Thread.Sleep(1000);
            wkr.ReportProgress(40, "Loading stuff 2...");
            //Here do your stuff
            Thread.Sleep(500);
            wkr.ReportProgress(80, "Loading stuff 3...");
            //Here do your stuff
            Thread.Sleep(1500);
            wkr.ReportProgress(90, "Loading stuff 4...");
            //Here do your stuff
            Thread.Sleep(2000);
            wkr.ReportProgress(100, "Finished");
        }

        void _mWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ProgressValue = e.ProgressPercentage; //Value
            ProgressMessage = e.UserState.ToString(); //Message
        }

        #region Properties
        public string ProgressMessage
        {
            get { return _progressMessage; }
            set
            {
                _progressMessage = value;
                OnPropertyChanged("ProgressMessage");
            }
        }

        public int ProgressValue
        {
            get { return _progressValue; }
            set
            {
                _progressValue = value;
                OnPropertyChanged("ProgressValue");
            }
        }
        #endregion



        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

And the resource dictionnary (for the flat bar, just in case)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style x:Key="FlatProgressBar" TargetType="{x:Type ProgressBar}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ProgressBar">
                    <Border BorderBrush="{x:Null}" BorderThickness="0" Background="{x:Null}" CornerRadius="0" Padding="0">
                        <Grid x:Name="PART_Track">
                            <Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="{Binding RelativeSource={RelativeSource AncestorType=ProgressBar},Path=Foreground}" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

This is working pretty well for me, tell me if you have some difficulties.

Here is a ptrscr of the result :

Result snapshot I hope it could help you.

BR,

Bastien.