// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // The Video View Model // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.ViewModels { using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; using System.ServiceModel.Channels; using System.Windows; using Caliburn.Micro; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Model.Encoding; using HandBrake.ApplicationServices.Parsing; using HandBrake.ApplicationServices.Services.Interfaces; using HandBrake.ApplicationServices.Utilities; using HandBrake.Interop; using HandBrake.Interop.Model.Encoding; using HandBrake.Interop.Model.Encoding.x264; using HandBrakeWPF.Commands.Interfaces; using HandBrakeWPF.Properties; using HandBrakeWPF.ViewModels.Interfaces; /// /// The Video View Model /// public class VideoViewModel : ViewModelBase, IVideoViewModel { #region Constants and Fields /// /// Same as source constant. /// private const string SameAsSource = "Same as source"; /// /// The possible h264 levels. /// private static readonly List Levels = new List { "Auto", "1.0", "1b", "1.1", "1.2", "1.3", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0", "4.1", "4.2", "5.0", "5.1", "5.2"}; /// /// Backing field for the user setting service. /// private readonly IUserSettingService userSettingService; /// /// The advanced encoder options command /// private readonly IAdvancedEncoderOptionsCommand advancedEncoderOptionsCommand; /// /// Backing field used to display / hide the x264 options /// private bool displayX264Options; /// /// The display qsv options. /// private bool displayQSVOptions; /// /// Backing field used to display / hide the h264 options /// private bool displayEncoderOptions; /// /// The quality max. /// private int qualityMax; /// /// The quality min. /// private int qualityMin; /// /// The show peak framerate. /// private bool showPeakFramerate; /// /// The show peak framerate. /// private int rf; /// /// The x264 preset value. /// private int x264PresetValue; /// /// The qsv preset value. /// private int qsvPresetValue; /// /// The extra arguments. /// private string extraArguments; /// /// The can clear tracker. /// private bool canClear; /// /// The use advanced tab. /// private bool useAdvancedTab; /// /// The display framerate controls. /// private bool displayNonQSVControls; #endregion #region Constructors and Destructors /// /// Initializes a new instance of the class. /// /// /// The user Setting Service. /// /// /// The advanced Encoder Options Command. /// public VideoViewModel(IUserSettingService userSettingService, IAdvancedEncoderOptionsCommand advancedEncoderOptionsCommand) { this.Task = new EncodeTask { VideoEncoder = VideoEncoder.X264 }; this.userSettingService = userSettingService; this.advancedEncoderOptionsCommand = advancedEncoderOptionsCommand; this.QualityMin = 0; this.QualityMax = 51; this.IsConstantQuantity = true; this.VideoEncoders = EnumHelper.GetEnumList(); X264Presets = new BindingList(EnumHelper.GetEnumList().ToList()); QsvPresets = new BindingList(EnumHelper.GetEnumList().ToList()); H264Profiles = EnumHelper.GetEnumList(); X264Tunes = EnumHelper.GetEnumList().Where(t => t != x264Tune.Fastdecode); this.H264Levels = Levels; this.userSettingService.SettingChanged += this.UserSettingServiceSettingChanged; } #endregion #region Public Properties /// /// Gets or sets the current Encode Task. /// public EncodeTask Task { get; set; } /// /// Gets a value indicating whether show advanced tab. /// public bool ShowAdvancedTab { get { bool showAdvTabSetting = this.userSettingService.GetUserSetting(UserSettingConstants.ShowAdvancedTab); if (!showAdvTabSetting) { this.UseAdvancedTab = false; } if (this.SelectedVideoEncoder == VideoEncoder.QuickSync) { return false; } return showAdvTabSetting; } } /// /// Gets or sets a value indicating whether use video tab. /// public bool UseAdvancedTab { get { return this.useAdvancedTab; } set { if (!object.Equals(value, this.useAdvancedTab)) { // Set the Advanced Tab up with the current settings, if we can. if (value) { this.Task.AdvancedEncoderOptions = this.GetActualx264Query(); } if (!value) { this.Task.AdvancedEncoderOptions = string.Empty; } this.useAdvancedTab = value; this.Task.ShowAdvancedTab = value; this.NotifyOfPropertyChange(() => this.UseAdvancedTab); } } } /// /// Gets Framerates. /// public IEnumerable Framerates { get { return new List { "Same as source", "5", "10", "12", "15", "23.976", "24", "25", "29.97", "30", "50", "59.94", "60" }; } } /// /// Gets or sets a value indicating whether IsConstantFramerate. /// public bool IsConstantFramerate { get { return this.Task.FramerateMode == FramerateMode.CFR; } set { if (value) { this.Task.FramerateMode = FramerateMode.CFR; this.IsVariableFramerate = false; this.IsPeakFramerate = false; } this.NotifyOfPropertyChange(() => this.IsConstantFramerate); } } /// /// Gets or sets a value indicating whether IsConstantQuantity. /// public bool IsConstantQuantity { get { return this.Task.VideoEncodeRateType == VideoEncodeRateType.ConstantQuality; } set { if (value) { this.Task.VideoEncodeRateType = VideoEncodeRateType.ConstantQuality; this.Task.TwoPass = false; this.Task.TurboFirstPass = false; this.Task.VideoBitrate = null; this.NotifyOfPropertyChange(() => this.Task); } else { this.Task.VideoEncodeRateType = VideoEncodeRateType.AverageBitrate; } this.NotifyOfPropertyChange(() => this.IsConstantQuantity); } } /// /// Gets or sets a value indicating whether IsPeakFramerate. /// public bool IsPeakFramerate { get { return this.Task.FramerateMode == FramerateMode.PFR; } set { if (value) { this.Task.FramerateMode = FramerateMode.PFR; this.IsVariableFramerate = false; this.IsConstantFramerate = false; } this.NotifyOfPropertyChange(() => this.IsPeakFramerate); } } /// /// Gets or sets a value indicating whether IsVariableFramerate. /// public bool IsVariableFramerate { get { return this.Task.FramerateMode == FramerateMode.VFR; } set { if (value) { this.IsPeakFramerate = false; this.IsConstantFramerate = false; this.Task.FramerateMode = FramerateMode.VFR; } this.NotifyOfPropertyChange(() => this.IsVariableFramerate); } } /// /// Gets a value indicating whether is lossless. /// public bool IsLossless { get { return 0.0.Equals(this.DisplayRF) && this.SelectedVideoEncoder == VideoEncoder.X264; } } /// /// Gets or sets QualityMax. /// public int QualityMax { get { return this.qualityMax; } set { if (!qualityMax.Equals(value)) { this.qualityMax = value; this.NotifyOfPropertyChange(() => this.QualityMax); } } } /// /// Gets or sets QualityMin. /// public int QualityMin { get { return this.qualityMin; } set { if (!qualityMin.Equals(value)) { this.qualityMin = value; this.NotifyOfPropertyChange(() => this.QualityMin); } } } /// /// Gets or sets RF. /// public int RF { get { return rf; } set { this.rf = value; double cqStep = userSettingService.GetUserSetting(UserSettingConstants.X264Step); this.SetQualitySliderBounds(); switch (this.SelectedVideoEncoder) { case VideoEncoder.FFMpeg: case VideoEncoder.FFMpeg2: this.Task.Quality = (32 - value); break; case VideoEncoder.QuickSync: case VideoEncoder.X264: double rfValue = 51.0 - value * cqStep; rfValue = Math.Round(rfValue, 2); this.Task.Quality = rfValue; break; case VideoEncoder.Theora: Task.Quality = value; break; } this.NotifyOfPropertyChange(() => this.RF); this.NotifyOfPropertyChange(() => this.DisplayRF); this.NotifyOfPropertyChange(() => this.IsLossless); } } /// /// Gets DisplayRF. /// public double DisplayRF { get { return Task.Quality.HasValue ? this.Task.Quality.Value : 0; } } /// /// Gets or sets a value indicating whether two pass. /// public bool TwoPass { get { return this.Task.TwoPass; } set { this.Task.TwoPass = value; this.NotifyOfPropertyChange(() => this.TwoPass); } } /// /// Gets or sets a value indicating whether turbo first pass. /// public bool TurboFirstPass { get { return this.Task.TurboFirstPass; } set { this.Task.TurboFirstPass = value; this.NotifyOfPropertyChange(() => this.TurboFirstPass); } } /// /// Gets the rfqp. /// public string Rfqp { get { return this.SelectedVideoEncoder == VideoEncoder.X264 ? "RF" : "QP"; } } /// /// Gets the high quality label. /// public string HighQualityLabel { get { return this.SelectedVideoEncoder == VideoEncoder.X264 ? Resources.Video_PlaceboQuality : Resources.Video_HigherQuality; } } /// /// Gets or sets SelectedFramerate. /// public string SelectedFramerate { get { if (this.Task.Framerate == null) { return "Same as source"; } return this.Task.Framerate.Value.ToString(CultureInfo.InvariantCulture); } set { if (value == "Same as source") { this.Task.Framerate = null; this.ShowPeakFramerate = false; if (this.Task.FramerateMode == FramerateMode.PFR) { this.IsVariableFramerate = true; } } else if (!string.IsNullOrEmpty(value)) { this.ShowPeakFramerate = true; if (this.Task.FramerateMode == FramerateMode.VFR) { this.IsPeakFramerate = true; } this.Task.Framerate = double.Parse(value, CultureInfo.InvariantCulture); } this.NotifyOfPropertyChange(() => this.SelectedFramerate); this.NotifyOfPropertyChange(() => this.Task); } } /// /// Gets or sets SelectedVideoEncoder. /// public VideoEncoder SelectedVideoEncoder { get { return this.Task.VideoEncoder; } set { this.Task.VideoEncoder = value; this.NotifyOfPropertyChange(() => this.SelectedVideoEncoder); // Tell the Advanced Panel off the change IAdvancedViewModel advancedViewModel = IoC.Get(); advancedViewModel.SetEncoder(this.Task.VideoEncoder); // Update the Quality Slider. Make sure the bounds are up to date with the users settings. this.SetQualitySliderBounds(); // Hide the x264 controls when not needed. this.DisplayX264Options = value == VideoEncoder.X264; this.DisplayQSVOptions = value == VideoEncoder.QuickSync; this.DisplayH264Options = value == VideoEncoder.X264 || value == VideoEncoder.QuickSync; this.UseAdvancedTab = value != VideoEncoder.QuickSync && this.UseAdvancedTab; this.DisplayNonQSVControls = value != VideoEncoder.QuickSync; this.NotifyOfPropertyChange(() => this.Rfqp); this.NotifyOfPropertyChange(() => this.ShowAdvancedTab); this.NotifyOfPropertyChange(() => this.HighQualityLabel); if (value == VideoEncoder.QuickSync) { this.IsConstantFramerate = true; this.TwoPass = false; this.TurboFirstPass = false; this.Task.Framerate = null; this.NotifyOfPropertyChange(() => SelectedFramerate); } } } /// /// Gets or sets a value indicating whether ShowPeakFramerate. /// public bool ShowPeakFramerate { get { return this.showPeakFramerate; } set { this.showPeakFramerate = value; this.NotifyOfPropertyChange(() => this.ShowPeakFramerate); } } /// /// Gets or sets VideoEncoders. /// public IEnumerable VideoEncoders { get; set; } /// /// Gets or sets the extra arguments. /// public string ExtraArguments { get { return this.Task.ExtraAdvancedArguments; } set { if (!object.Equals(this.Task.ExtraAdvancedArguments, value)) { this.Task.ExtraAdvancedArguments = value; this.NotifyOfPropertyChange(() => this.ExtraArguments); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } } /// /// Gets or sets a value indicating whether to display H264 /// public bool DisplayH264Options { get { return this.displayEncoderOptions; } set { this.displayEncoderOptions = value; this.NotifyOfPropertyChange(() => this.DisplayH264Options); } } /// /// Gets or sets a value indicating whether display x 264 options. /// public bool DisplayX264Options { get { return this.displayX264Options; } set { this.displayX264Options = value; this.NotifyOfPropertyChange(() => this.DisplayX264Options); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } /// /// Gets or sets a value indicating whether to display qsv options. /// public bool DisplayQSVOptions { get { return this.displayQSVOptions; } set { this.displayQSVOptions = value; this.NotifyOfPropertyChange(() => this.DisplayQSVOptions); } } /// /// Gets or sets a value indicating whether display framerate controls. /// public bool DisplayNonQSVControls { get { return this.displayNonQSVControls; } set { this.displayNonQSVControls = value; this.NotifyOfPropertyChange(() => this.DisplayNonQSVControls); } } /// /// Gets or sets the x 264 preset value. /// public int X264PresetValue { get { return this.x264PresetValue; } set { if (!object.Equals(this.X264PresetValue, value)) { this.x264PresetValue = value; this.X264Preset = this.X264Presets[value]; this.NotifyOfPropertyChange(() => this.x264PresetValue); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } } /// /// Gets or sets X264Preset. /// public x264Preset X264Preset { get { return this.Task.X264Preset; } set { if (!object.Equals(this.X264Preset, value)) { this.Task.X264Preset = value; this.NotifyOfPropertyChange(() => this.X264Preset); ResetAdvancedTab(); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } } /// /// Gets or sets X264Preset. /// public QsvPreset QsvPreset { get { return this.Task.QsvPreset; } set { if (!object.Equals(this.QsvPreset, value)) { this.Task.QsvPreset = value; this.NotifyOfPropertyChange(() => this.QsvPreset); } } } /// /// Gets or sets the x 264 preset value. /// public int QsvPresetValue { get { return this.qsvPresetValue; } set { if (!object.Equals(this.QsvPresetValue, value)) { this.qsvPresetValue = value; this.QsvPreset = this.QsvPresets[value]; this.NotifyOfPropertyChange(() => this.QsvPresetValue); } } } /// /// Gets or sets H264Profile. /// public x264Profile H264Profile { get { return this.Task.H264Profile; } set { if (!object.Equals(this.H264Profile, value)) { this.Task.H264Profile = value; this.NotifyOfPropertyChange(() => this.H264Profile); ResetAdvancedTab(); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } } /// /// Gets or sets H264Profile. /// public string H264Level { get { return this.Task.H264Level; } set { if (!object.Equals(this.H264Level, value)) { this.Task.H264Level = value; this.NotifyOfPropertyChange(() => this.H264Level); ResetAdvancedTab(); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } } /// /// Gets or sets X264Tune. /// public x264Tune X264Tune { get { return this.Task.X264Tune; } set { if (!object.Equals(this.X264Tune, value)) { this.Task.X264Tune = value; this.NotifyOfPropertyChange(() => this.X264Tune); ResetAdvancedTab(); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } } /// /// Gets or sets a value indicating whether fast decode. /// public bool FastDecode { get { return this.Task.FastDecode; } set { if (!object.Equals(this.FastDecode, value)) { this.Task.FastDecode = value; this.NotifyOfPropertyChange(() => this.FastDecode); ResetAdvancedTab(); this.NotifyOfPropertyChange(() => FullOptionsTooltip); } } } /// /// Gets or sets X264Presets. /// public BindingList X264Presets { get; set; } /// /// Gets or sets QsvPreset. /// public BindingList QsvPresets { get; set; } /// /// Gets or sets X264Profiles. /// public IEnumerable H264Profiles { get; set; } /// /// Gets or sets X264Tunes. /// public IEnumerable X264Tunes { get; set; } /// /// Gets or sets the x 264 levels. /// public IEnumerable H264Levels { get; set; } /// /// Gets the full options tooltip. /// public string FullOptionsTooltip { get { return string.Format(Resources.Video_x264ExtraArgs, this.GetActualx264Query()); // "You can provide additional arguments using the standard x264 format"; } } /// /// Gets the qsv slider max. /// public int QsvSliderMax { get { return SystemInfo.IsHswOrNewer ? 2 : 1; } } #endregion #region Public Methods /// /// Setup this window for a new source /// /// /// The title. /// /// /// The preset. /// /// /// The task. /// public void SetSource(Title title, Preset preset, EncodeTask task) { this.Task = task; } /// /// Setup this tab for the specified preset. /// /// /// The preset. /// /// /// The task. /// public void SetPreset(Preset preset, EncodeTask task) { this.Task = task; if (preset == null || preset.Task == null) { return; } this.SelectedVideoEncoder = preset.Task.VideoEncoder; this.SelectedFramerate = preset.Task.Framerate.HasValue ? preset.Task.Framerate.Value.ToString(CultureInfo.InvariantCulture) : SameAsSource; this.IsConstantQuantity = preset.Task.VideoEncodeRateType == VideoEncodeRateType.ConstantQuality; switch (preset.Task.FramerateMode) { case FramerateMode.CFR: this.IsConstantFramerate = true; break; case FramerateMode.VFR: this.IsVariableFramerate = true; this.ShowPeakFramerate = false; break; case FramerateMode.PFR: this.IsPeakFramerate = true; this.ShowPeakFramerate = true; break; } double cqStep = userSettingService.GetUserSetting(UserSettingConstants.X264Step); double rfValue = 0; this.SetQualitySliderBounds(); switch (this.SelectedVideoEncoder) { case VideoEncoder.FFMpeg: case VideoEncoder.FFMpeg2: if (preset.Task.Quality.HasValue) { int cq; int.TryParse(preset.Task.Quality.Value.ToString(CultureInfo.InvariantCulture), out cq); this.RF = 32 - cq; } break; case VideoEncoder.QuickSync: case VideoEncoder.X264: double multiplier = 1.0 / cqStep; if (preset.Task.Quality.HasValue) { rfValue = preset.Task.Quality.Value * multiplier; } this.RF = this.QualityMax - (int)Math.Round(rfValue, 0); break; case VideoEncoder.Theora: if (preset.Task.Quality.HasValue) { this.RF = (int)preset.Task.Quality.Value; } break; } this.Task.TwoPass = preset.Task.TwoPass; this.Task.TurboFirstPass = preset.Task.TurboFirstPass; this.Task.VideoBitrate = preset.Task.VideoBitrate; this.NotifyOfPropertyChange(() => this.Task); if (preset.Task != null) { this.SetEncoder(preset.Task.VideoEncoder); // applies to both x264 and QSV if (preset.Task.VideoEncoder == VideoEncoder.X264 || preset.Task.VideoEncoder == VideoEncoder.QuickSync) { this.H264Profile = preset.Task.H264Profile; this.H264Level = preset.Task.H264Level; } else { this.H264Profile = x264Profile.None; this.H264Level = "Auto"; } // x264 Only if (preset.Task.VideoEncoder == VideoEncoder.X264) { this.X264PresetValue = (int)preset.Task.X264Preset; this.X264Tune = preset.Task.X264Tune; this.FastDecode = preset.Task.FastDecode; } else { this.X264PresetValue = (int)x264Preset.Medium; this.X264Tune = x264Tune.None; this.FastDecode = false; } // QSV Only if (preset.Task.VideoEncoder == VideoEncoder.QuickSync) { this.QsvPresetValue = (int)preset.Task.QsvPreset; } else { this.QsvPresetValue = SystemInfo.IsHswOrNewer ? (int)QsvPreset.Quality : (int)QsvPreset.Balanced; } this.ExtraArguments = preset.Task.ExtraAdvancedArguments; this.UseAdvancedTab = !string.IsNullOrEmpty(preset.Task.AdvancedEncoderOptions) && this.ShowAdvancedTab; } } /// /// Update all the UI controls based on the encode task passed in. /// /// /// The task. /// public void UpdateTask(EncodeTask task) { this.Task = task; this.NotifyOfPropertyChange(() => this.IsConstantFramerate); this.NotifyOfPropertyChange(() => this.IsConstantQuantity); this.NotifyOfPropertyChange(() => this.IsPeakFramerate); this.NotifyOfPropertyChange(() => this.IsVariableFramerate); this.NotifyOfPropertyChange(() => this.SelectedVideoEncoder); this.NotifyOfPropertyChange(() => this.SelectedFramerate); this.NotifyOfPropertyChange(() => this.RF); this.NotifyOfPropertyChange(() => this.DisplayRF); this.NotifyOfPropertyChange(() => this.Task.VideoBitrate); this.NotifyOfPropertyChange(() => this.Task.TwoPass); this.NotifyOfPropertyChange(() => this.Task.TurboFirstPass); this.NotifyOfPropertyChange(() => this.X264Tune); this.NotifyOfPropertyChange(() => this.X264Preset); this.NotifyOfPropertyChange(() => this.H264Level); this.NotifyOfPropertyChange(() => this.H264Profile); this.NotifyOfPropertyChange(() => this.FastDecode); this.NotifyOfPropertyChange(() => this.ExtraArguments); this.NotifyOfPropertyChange(() => this.QsvPreset); } /// /// Set the currently selected encoder. /// /// /// The Video Encoder. /// public void SetEncoder(VideoEncoder encoder) { this.DisplayH264Options = encoder == VideoEncoder.X264 || encoder == VideoEncoder.QuickSync; this.DisplayX264Options = encoder == VideoEncoder.X264; this.DisplayQSVOptions = encoder == VideoEncoder.QuickSync; if (encoder == VideoEncoder.QuickSync) { this.UseAdvancedTab = false; } } /// /// Trigger a Notify Property Changed on the Task to force various UI elements to update. /// public void RefreshTask() { this.NotifyOfPropertyChange(() => this.Task); if ((Task.OutputFormat == OutputFormat.Mp4) && this.SelectedVideoEncoder == VideoEncoder.Theora) { this.SelectedVideoEncoder = VideoEncoder.X264; } } /// /// Clear advanced settings. /// public void ClearAdvancedSettings() { this.canClear = false; this.X264PresetValue = 5; this.X264Tune = x264Tune.None; this.H264Profile = x264Profile.None; this.FastDecode = false; this.H264Level = "Auto"; this.ExtraArguments = string.Empty; this.canClear = true; } /// /// The copy query. /// public void CopyQuery() { Clipboard.SetDataObject(this.SelectedVideoEncoder == VideoEncoder.X264 ? this.GetActualx264Query() : this.ExtraArguments); } #endregion /// /// Set the bounds of the Constant Quality Slider /// private void SetQualitySliderBounds() { // Note Updating bounds to the same values won't trigger an update. // The properties are smart enough to not take in equal values. switch (this.SelectedVideoEncoder) { case VideoEncoder.FFMpeg: case VideoEncoder.FFMpeg2: this.QualityMin = 1; this.QualityMax = 31; break; case VideoEncoder.X264: case VideoEncoder.QuickSync: this.QualityMin = 0; this.QualityMax = (int)(51 / userSettingService.GetUserSetting(UserSettingConstants.X264Step)); break; case VideoEncoder.Theora: this.QualityMin = 0; this.QualityMax = 63; break; } } /// /// Reset advanced tab. /// private void ResetAdvancedTab() { if (canClear) { this.advancedEncoderOptionsCommand.ExecuteClearAdvanced(); } } /// /// The get actualx 264 query. /// /// /// The . /// private string GetActualx264Query() { if (!GeneralUtilities.IsLibHbPresent) { return string.Empty; // Feature is disabled. } string preset = EnumHelper.GetDisplay(this.X264Preset).ToLower().Replace(" ", string.Empty); string profile = EnumHelper.GetDisplay(this.H264Profile).ToLower(); List tunes = new List(); if (X264Tune != x264Tune.None) { tunes.Add(this.X264Tune.ToString().ToLower().Replace(" ", string.Empty)); // TODO tidy this sillyness up. } if (this.FastDecode) { tunes.Add("fastdecode"); } // Get the width or height, default if we don't have it yet so we don't crash. int width = this.Task.Width.HasValue ? this.Task.Width.Value : 720; int height = this.Task.Height.HasValue ? this.Task.Height.Value : 576; if (height == 0) { height = 576; } if (width == 0) { width = 720; } try { return HandBrakeUtils.CreateX264OptionsString( preset, tunes, this.ExtraArguments, profile, this.H264Level, width, height); } catch (Exception) { return "Error: Libhb not loaded."; } } /// /// The user setting service_ setting changed. /// /// /// The sender. /// /// /// The e. /// private void UserSettingServiceSettingChanged(object sender, HandBrake.ApplicationServices.EventArgs.SettingChangedEventArgs e) { if (e.Key == UserSettingConstants.ShowAdvancedTab) { this.NotifyOfPropertyChange(() => this.ShowAdvancedTab); } } } }