WPF unity container fired singleton service twice

42 Views Asked by At

Here is the program structure, App > Window > DataContext binding to MainViewModel

The MainViewModel contains 3 sub-ViewModel property, named as

  • ViewModelA
  • ViewModelB
  • ViewModelC

each of sub-viewModel contains a dispatchertimer to get data from API and display on WPF.

I am going to inject a common voice service into all sub-viewModel, that will used by sub-viewModel to play voice.

The voiceService designed as singleton and allows sub-viewModel to add data, voiceService running a timer that watches on a List, play voice when new data arrived.

But I found the unity container fires the service twice, did my setting is incorrect

// MainWindow.xaml.cs
                VoiceService voiceService = new VoiceService();
                AutoMapperService autoMapperService = new AutoMapperService();
                this.DataContext = new MainViewModel(voiceService, autoMapperService);
                //this.DataContext = _container.Resolve<IMainViewModel>();
// app.xaml.cs
private void InitContainer(IUnityContainer container)
        {
            container.RegisterType<IMainViewModel, MainViewModel>();
            container.RegisterType<IVoiceService, VoiceService>();
            container.RegisterType<IAutoMapperService, AutoMapperService>();

            // for Unity 5, Unity has been broken down into a set of Packages for you to install only what you need.
            // If you need to do Registration By Convention -
            // which is what the RegisterTypes() method is used for,
            // you need to also install the NuGet Package,
            // Unity.RegistrationByConvention(version 2.1.0 as of this writing).

            // With Unity >=3, you can skip the container registration if you follow the naming convention like this:
            // This will register all types with a ISample/Sample naming convention 
            //container.RegisterTypes(
            //    AllClasses.FromLoadedAssemblies(),
            //    WithMappings.FromMatchingInterface,
            //    WithName.Default);
        }
public class VoiceService : IVoiceService, IDisposable
    {
        protected readonly System.Timers.Timer announceTimer;
        protected readonly int defaultDataTimeInterval = 10;

        private List<VoiceAnnouncement> announcementQueueList = new List<VoiceAnnouncement>();
        private List<VoiceAnnouncement> announcedRecordList = new List<VoiceAnnouncement>();
        
        public VoiceAnnouncement currentAnnouncement = new VoiceAnnouncement();

        private SpeechSynthesizer speaker = new SpeechSynthesizer();
        private volatile bool _isCurrentlySpeaking = false;

        /// <summary>Event handler. Fired when the SpeechSynthesizer object starts speaking asynchronously.</summary>
        private void StartedSpeaking(object sender, SpeakStartedEventArgs e)
        { this.GetInstance()._isCurrentlySpeaking = true; }
        /// <summary>Event handler. Fired when the SpeechSynthesizer object finishes speaking asynchronously.</summary>
        private void FinishedSpeaking(object sender, SpeakCompletedEventArgs e)
        { this.GetInstance()._isCurrentlySpeaking = false; }

        public event EventHandler OnSomeEvent = delegate { };
        public bool IsCurrentlySpeaking
        {
            get { return this._isCurrentlySpeaking; }
        }

        private static readonly Lazy<VoiceService> lazyAnnounceService = new Lazy<VoiceService>(() => new VoiceService());

        public VoiceService()
        {
            // don't use dispatchertime, use timer
            // otherwise the screen will freeze when speak
            this.announceTimer = new System.Timers.Timer(TimeSpan.FromSeconds(this.defaultDataTimeInterval).TotalMilliseconds);
            this.announceTimer = new System.Timers.Timer(5000);
            announceTimer.Elapsed += PlayVoiceTimerTickTest;
            announceTimer.Start();

            //this.announceTimer = new DispatcherTimer();
            //announceTimer.Interval = TimeSpan.FromSeconds(this.defaultDataTimeInterval);
            //announceTimer.Tick += PlayVoiceTimerTick;
            //announceTimer.Start();

            this.speaker.SpeakStarted += new EventHandler<SpeakStartedEventArgs>(StartedSpeaking);
            this.speaker.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(FinishedSpeaking);
        }
        
        
        public VoiceService GetInstance()
        {
            return lazyAnnounceService.Value;
        }


        void IDisposable.Dispose()
        {
            this.announceTimer.Elapsed -= this.PlayVoiceTimerTickTest;
            this.speaker.Dispose();
        }
0

There are 0 best solutions below