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(); } }); }