public Example2ViewModel(Window window)
        {
            _libVLC     = new LibVLC();
            MediaPlayer = new MediaPlayer(_libVLC);
            bool operationActive = false;
            var  refresh         = new Subject <Unit>();

            //disable events while some operations active, as sometimes causing deadlocks
            IObservable <Unit> Wrap(IObservable <Unit> obs)
            => obs.Where(_ => !operationActive).Merge(refresh).ObserveOn(AvaloniaScheduler.Instance);

            IObservable <Unit> VLCEvent(string name)
            => Observable.FromEventPattern(MediaPlayer, name).Select(_ => Unit.Default);

            void Op(Action action)
            {
                operationActive = true;
                action();
                operationActive = false;
                refresh.OnNext(Unit.Default);
            };

            var positionChanged = VLCEvent(nameof(MediaPlayer.PositionChanged));
            var playingChanged  = VLCEvent(nameof(MediaPlayer.Playing));
            var stoppedChanged  = VLCEvent(nameof(MediaPlayer.Stopped));
            var timeChanged     = VLCEvent(nameof(MediaPlayer.TimeChanged));
            var lengthChanged   = VLCEvent(nameof(MediaPlayer.LengthChanged));
            var muteChanged     = VLCEvent(nameof(MediaPlayer.Muted))
                                  .Merge(VLCEvent(nameof(MediaPlayer.Unmuted)));
            var endReachedChanged  = VLCEvent(nameof(MediaPlayer.EndReached));
            var pausedChanged      = VLCEvent(nameof(MediaPlayer.Paused));
            var volumeChanged      = VLCEvent(nameof(MediaPlayer.VolumeChanged));
            var stateChanged       = Observable.Merge(playingChanged, stoppedChanged, endReachedChanged, pausedChanged);
            var hasMediaObservable = this.WhenAnyValue(v => v.MediaUrl, v => !string.IsNullOrEmpty(v));
            var fullState          = Observable.Merge(
                stateChanged,
                VLCEvent(nameof(MediaPlayer.NothingSpecial)),
                VLCEvent(nameof(MediaPlayer.Buffering)),
                VLCEvent(nameof(MediaPlayer.EncounteredError))
                );

            _subscriptions = new CompositeDisposable
            {
                Wrap(positionChanged).DistinctUntilChanged(_ => Position).Subscribe(_ => this.RaisePropertyChanged(nameof(Position))),
                Wrap(timeChanged).DistinctUntilChanged(_ => CurrentTime).Subscribe(_ => this.RaisePropertyChanged(nameof(CurrentTime))),
                Wrap(lengthChanged).DistinctUntilChanged(_ => Duration).Subscribe(_ => this.RaisePropertyChanged(nameof(Duration))),
                Wrap(muteChanged).DistinctUntilChanged(_ => IsMuted).Subscribe(_ => this.RaisePropertyChanged(nameof(IsMuted))),
                Wrap(fullState).DistinctUntilChanged(_ => State).Subscribe(_ => this.RaisePropertyChanged(nameof(State))),
                Wrap(volumeChanged).DistinctUntilChanged(_ => Volume).Subscribe(_ => this.RaisePropertyChanged(nameof(Volume))),
                Wrap(fullState).DistinctUntilChanged(_ => Information).Subscribe(_ => this.RaisePropertyChanged(nameof(Information)))
            };

            bool active() => _subscriptions == null ? false : MediaPlayer.IsPlaying || MediaPlayer.CanPause;

            stateChanged = Wrap(stateChanged);

            PlayCommand = ReactiveCommand.Create(
                () => Op(() =>
            {
                string absolute   = new Uri(MediaUrl).AbsoluteUri;
                bool isfile       = absolute.StartsWith("file://");
                MediaPlayer.Media = new Media(_libVLC, MediaUrl, isfile ? FromType.FromPath : FromType.FromLocation);
                MediaPlayer.Play();
            }),
                hasMediaObservable);

            StopCommand = ReactiveCommand.Create(
                () => Op(() => MediaPlayer.Stop()),
                stateChanged.Select(_ => active()));

            PauseCommand = ReactiveCommand.Create(
                () => MediaPlayer.Pause(),
                stateChanged.Select(_ => active()));

            ForwardCommand              = ReactiveCommand.Create(
                () => MediaPlayer.Time += 1000,
                stateChanged.Select(_ => active()));

            BackwardCommand             = ReactiveCommand.Create(
                () => MediaPlayer.Time -= 1000,
                stateChanged.Select(_ => active()));

            NextFrameCommand = ReactiveCommand.Create(
                () => MediaPlayer.NextFrame(),
                stateChanged.Select(_ => active()));

            OpenCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                var fd = new OpenFileDialog()
                {
                    AllowMultiple = false
                };
                var res = await fd.ShowAsync(window);
                if (res.Any())
                {
                    MediaUrl = res.FirstOrDefault();
                    Dispatcher.UIThread.InvokeAsync(() => PlayCommand.Execute(null));
                }
            });

            MediaUrl = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";

            Wrap(playingChanged).Subscribe(_ =>
            {
                if (!_played.Contains(MediaUrl))
                {
                    _played.Add(MediaUrl);
                    SavePlayed();
                }
            });
        }