//******************************************************************************************************// OutputStream.cs - Gbtc//// Copyright © 2010, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 07/26/2011 - Magdiel Lorenzo// Generated original version of source code.// 09/08/2011 - Mehulbhai Thakkar// Modified code to use SQL queries directly instead from script file resource.// Added comments to all properties and static methods.// 09/14/2012 - Aniket Salver // Added paging and sorting technique. // 03/08/2017 - J. Ritchie Carroll// Modified UI code to auto-set assign default auto publish config frame based on selections.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.ComponentModel;using System.ComponentModel.DataAnnotations;using System.Data;using System.Globalization;using System.Linq;using System.Text.RegularExpressions;using System.Windows;using System.Windows.Data;using GSF.ComponentModel.DataAnnotations;using GSF.Data;using GSF.Diagnostics;using GSF.PhasorProtocols.IEEEC37_118;using GSF.TimeSeries.UI;using GSF.TimeSeries.UI.DataModels;using Measurement = GSF.TimeSeries.UI.DataModels.Measurement;using C37Concentrator = PhasorProtocolAdapters.IeeeC37_118.Concentrator; // ReSharper disable ConstantConditionalAccessQualifier// ReSharper disable AccessToDisposedClosure// ReSharper disable ConstantConditionalAccessQualifiernamespace GSF.PhasorProtocols.UI.DataModels{ /// <summary> /// Supported Synchrophasor Output Protocols. /// </summary> public enum OutputProtocol { /// <summary> /// IEEE C37.118-2011 Output. /// </summary> IEEE_C37_118_2011 = 3, /// <summary> /// IEEE C37.118-2005 Output. /// </summary> IEEE_C37_118_2005 = 0, /// <summary> /// BPA PDCstream Output. /// </summary> BPA_PDCSTREAM = 1, /// <summary> /// IEC 61850-90-5 Output. /// </summary> IEC_61850_90_5 = 2 } /// <summary> /// Defines a value converter for the <see cref="OutputProtocol"/> enumeration. /// </summary> public class OutputProtocolValueConverter : IValueConverter { /// <summary>Converts a value.</summary> /// <param name="value">The value produced by the binding source.</param> /// <param name="targetType">The type of the binding target property.</param> /// <param name="parameter">The converter parameter to use.</param> /// <param name="culture">The culture to use in the converter.</param> /// <returns>A converted value. If the method returns <see langword="null" />, the valid null value is used.</returns> public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is null) return null; if (parameter is null) return null; if (parameter is not CollectionViewSource viewSource) return null; if (viewSource.Source is not Dictionary<OutputProtocol, string> typeList) return null; string name = value.ToString(); if (Enum.TryParse(name, out OutputProtocol type) && typeList.TryGetValue(type, out string typeName)) return new KeyValuePair<OutputProtocol, string>(type, typeName); return null; } /// <summary>Converts a value.</summary> /// <param name="value">The value that is produced by the binding target.</param> /// <param name="targetType">The type to convert to.</param> /// <param name="parameter">The converter parameter to use.</param> /// <param name="culture">The culture to use in the converter.</param> /// <returns>A converted value. If the method returns <see langword="null" />, the valid null value is used.</returns> public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value is KeyValuePair<OutputProtocol, string> pair ? (object)pair.Key : null; } /// <summary> /// Gets default instance of the <see cref="OutputProtocolValueConverter"/>. /// </summary> public static readonly OutputProtocolValueConverter Default = new(); } /// <summary> /// Represents a record of <see cref="OutputStream"/> as defined in the database. /// </summary> public class OutputStream : DataModelBase { #region [ Members ] private Guid m_nodeID; private int m_ID; private string m_acronym; private string m_name; private OutputProtocol m_type = OutputProtocol.IEEE_C37_118_2005; private string m_connectionString; private int m_idCode; private string m_commandChannel; private string m_dataChannel; private bool m_autoPublishConfigFrame; private bool m_autoStartDataChannel; private int m_nominalFrequency; private int m_framesPerSecond; private double m_lagTime; private double m_leadTime; private bool m_useLocalClockAsRealTime; private bool m_allowSortsByArrival; private int m_loadOrder; private bool m_enabled; private bool m_ignoreBadTimeStamps; private int m_timeResolution; private bool m_allowPreemptivePublishing; private string m_downsamplingMethod; private string m_dataFormat; private string m_coordinateFormat; private int m_currentScalingValue; private int m_voltageScalingValue; private int m_analogScalingValue; private int m_digitalMaskValue; private bool m_performTimestampReasonabilityCheck; private bool m_roundToNearestTimestamp; private string m_mirroringSourceDevice = ""; // ReSharper disable once MemberInitializerValueIgnored // Assign initial changed state to true before calling base class constructor call to prevent unintended updates during default value initialization private bool m_autoPublishConfigFrameChangedByUser = true; // Called 1st #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="OutputStream"/>. /// </summary> public OutputStream() : base(false) // Called 2nd { // Post base class constructor call, reset changed state value back to false m_autoPublishConfigFrameChangedByUser = false; // Called 3rd try { // Set default lead/lag time settings to those used by manager screens object lagTimeValue = IsolatedStorageManager.ReadFromIsolatedStorage("LagTime"); if (lagTimeValue is not null && double.TryParse(lagTimeValue.ToString(), out double lagTime) && lagTime > 0.0D) m_lagTime = lagTime; object leadTimeValue = IsolatedStorageManager.ReadFromIsolatedStorage("LeadTime"); if (leadTimeValue is not null && double.TryParse(leadTimeValue.ToString(), out double leadTime) && leadTime > 0.0D) m_leadTime = leadTime; } catch (Exception ex) { Logger.SwallowException(ex); } } #endregion #region [ Properties ] /// <summary> /// Gets or sets function to call when config frame size calculation should be updated. /// </summary> public Action UpdateConfigFrameSize { get; set; } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s NodeID. /// </summary> public Guid NodeID { get => m_nodeID; set { m_nodeID = value; OnPropertyChanged("NodeID"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s ID. /// </summary> // Field is populated by database via auto-increment and has no screen interaction, so no validation attributes are applied. public int ID { get => m_ID; set { m_ID = value; OnPropertyChanged("ID"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Acronym. /// </summary> [Required(ErrorMessage = "Output stream acronym is a required field, please provide value.")] [StringLength(200, ErrorMessage = "Output stream acronym cannot exceed 200 characters.")] [AcronymValidation] public string Acronym { get => m_acronym; set { m_acronym = value; OnPropertyChanged("Acronym"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Name. /// </summary> [StringLength(200, ErrorMessage = "Output stream name cannot exceed 200 characters.")] public string Name { get => m_name; set { m_name = value; OnPropertyChanged("Name"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s output protocol type. /// </summary> [Required(ErrorMessage = "Output stream type is a required, please provide a value.")] public OutputProtocol Type { get => m_type; set { const string ConfigTypeKey = nameof(C37Concentrator.TargetConfigurationType); m_type = value; Dictionary<string, string> settings = ConnectionString?.ParseKeyValuePairs() ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); switch (m_type) { case OutputProtocol.IEEE_C37_118_2011: settings[ConfigTypeKey] = DraftRevision.Std2011.ToString(); break; case OutputProtocol.IEEE_C37_118_2005: settings[ConfigTypeKey] = DraftRevision.Std2005.ToString(); break; default: settings.Remove(ConfigTypeKey); break; } ConnectionString = settings.JoinKeyValuePairs(); OnPropertyChanged("Type"); UpdateConfigFrameSize?.Invoke(); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s ConnectionString. /// </summary> [DefaultValue("addPhaseLabelSuffix=false; replaceWithSpaceChar=_")] public string ConnectionString { get => m_connectionString; set { Dictionary<string, string> settings = value.ParseKeyValuePairs(); if (settings.TryGetValue(nameof(RoundToNearestTimestamp), out string setting)) { RoundToNearestTimestamp = setting.ParseBoolean(); settings.Remove(nameof(RoundToNearestTimestamp)); m_connectionString = settings.JoinKeyValuePairs(); } else { m_connectionString = value; } OnPropertyChanged("ConnectionString"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s IDCode. /// </summary> [Required(ErrorMessage = "Output stream IDCode is a required field, please provide a value.")] public int IDCode { get => m_idCode; set { m_idCode = value; OnPropertyChanged("IDCode"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s CommandChannel. /// </summary> public string CommandChannel { get => m_commandChannel; set { m_commandChannel = value; SetDefaultAutoPublishConfigFrameState(); OnPropertyChanged("CommandChannel"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s DataChannel. /// </summary> public string DataChannel { get => m_dataChannel; set { m_dataChannel = value; SetDefaultAutoPublishConfigFrameState(); OnPropertyChanged("DataChannel"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s AutoPublishConfigFrame flag. /// </summary> [Required(ErrorMessage = "Output stream auto publish config frame is a required field, please provide a value.")] [DefaultValue(false)] public bool AutoPublishConfigFrame { get => m_autoPublishConfigFrame; set { m_autoPublishConfigFrame = value; m_autoPublishConfigFrameChangedByUser = true; OnPropertyChanged("AutoPublishConfigFrame"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s AutoStartDataChannel flag. /// </summary> [Required(ErrorMessage = "Output stream auto start data channel is a required field, please provide a value.")] [DefaultValue(true)] public bool AutoStartDataChannel { get => m_autoStartDataChannel; set { m_autoStartDataChannel = value; OnPropertyChanged("AutoStartDataChannel"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Nominal Frequency. /// </summary> [Required(ErrorMessage = "Output stream nominal frequency is a required field, please provide a value.")] [DefaultValue(60)] public int NominalFrequency { get => m_nominalFrequency; set { m_nominalFrequency = value; OnPropertyChanged("NominalFrequency"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Frames Per Second. /// </summary> [Required(ErrorMessage = "Output stream frames per second is a required field, please provide a value.")] [DefaultValue(30)] public int FramesPerSecond { get => m_framesPerSecond; set { m_framesPerSecond = value; OnPropertyChanged("FramesPerSecond"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s LagTime. /// </summary> [Required(ErrorMessage = "Output stream lag time is a required field, please provide a value.")] [DefaultValue(3.0)] public double LagTime { get => m_lagTime; set { m_lagTime = value; OnPropertyChanged("LagTime"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s LeadTime. /// </summary> [Required(ErrorMessage = "Output stream lead time is a required field, please provide a value.")] [DefaultValue(1.0)] public double LeadTime { get => m_leadTime; set { m_leadTime = value; OnPropertyChanged("LeadTime"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s UseLocalClockAsRealTime flag. /// </summary> [Required(ErrorMessage = "Output stream use local clock as real-time is a required field, please provide a value.")] [DefaultValue(false)] public bool UseLocalClockAsRealTime { get => m_useLocalClockAsRealTime; set { m_useLocalClockAsRealTime = value; OnPropertyChanged("UseLocalClockAsRealTime"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s AllowSortsByArrival flag. /// </summary> [Required(ErrorMessage = "Output stream allow sorts by arrival is a required field, please provide a value.")] [DefaultValue(true)] public bool AllowSortsByArrival { get => m_allowSortsByArrival; set { m_allowSortsByArrival = value; OnPropertyChanged("AllowSortsByArrival"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s LoadOrder. /// </summary> [Required(ErrorMessage = "Output stream load order is a required field, please provide a value.")] [DefaultValue(0)] public int LoadOrder {Lines 1–500 of 1211. Load more
//****************************************************************************************************** // OutputStream.cs - Gbtc // // Copyright © 2010, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 07/26/2011 - Magdiel Lorenzo // Generated original version of source code. // 09/08/2011 - Mehulbhai Thakkar // Modified code to use SQL queries directly instead from script file resource. // Added comments to all properties and static methods. // 09/14/2012 - Aniket Salver // Added paging and sorting technique. // 03/08/2017 - J. Ritchie Carroll // Modified UI code to auto-set assign default auto publish config frame based on selections. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Data; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Data; using GSF.ComponentModel.DataAnnotations; using GSF.Data; using GSF.Diagnostics; using GSF.PhasorProtocols.IEEEC37_118; using GSF.TimeSeries.UI; using GSF.TimeSeries.UI.DataModels; using Measurement = GSF.TimeSeries.UI.DataModels.Measurement; using C37Concentrator = PhasorProtocolAdapters.IeeeC37_118.Concentrator; // ReSharper disable ConstantConditionalAccessQualifier // ReSharper disable AccessToDisposedClosure // ReSharper disable ConstantConditionalAccessQualifier namespace GSF.PhasorProtocols.UI.DataModels { /// <summary> /// Supported Synchrophasor Output Protocols. /// </summary> public enum OutputProtocol { /// <summary> /// IEEE C37.118-2011 Output. /// </summary> IEEE_C37_118_2011 = 3, /// <summary> /// IEEE C37.118-2005 Output. /// </summary> IEEE_C37_118_2005 = 0, /// <summary> /// BPA PDCstream Output. /// </summary> BPA_PDCSTREAM = 1, /// <summary> /// IEC 61850-90-5 Output. /// </summary> IEC_61850_90_5 = 2 } /// <summary> /// Defines a value converter for the <see cref="OutputProtocol"/> enumeration. /// </summary> public class OutputProtocolValueConverter : IValueConverter { /// <summary>Converts a value.</summary> /// <param name="value">The value produced by the binding source.</param> /// <param name="targetType">The type of the binding target property.</param> /// <param name="parameter">The converter parameter to use.</param> /// <param name="culture">The culture to use in the converter.</param> /// <returns>A converted value. If the method returns <see langword="null" />, the valid null value is used.</returns> public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is null) return null; if (parameter is null) return null; if (parameter is not CollectionViewSource viewSource) return null; if (viewSource.Source is not Dictionary<OutputProtocol, string> typeList) return null; string name = value.ToString(); if (Enum.TryParse(name, out OutputProtocol type) && typeList.TryGetValue(type, out string typeName)) return new KeyValuePair<OutputProtocol, string>(type, typeName); return null; } /// <summary>Converts a value.</summary> /// <param name="value">The value that is produced by the binding target.</param> /// <param name="targetType">The type to convert to.</param> /// <param name="parameter">The converter parameter to use.</param> /// <param name="culture">The culture to use in the converter.</param> /// <returns>A converted value. If the method returns <see langword="null" />, the valid null value is used.</returns> public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value is KeyValuePair<OutputProtocol, string> pair ? (object)pair.Key : null; } /// <summary> /// Gets default instance of the <see cref="OutputProtocolValueConverter"/>. /// </summary> public static readonly OutputProtocolValueConverter Default = new(); } /// <summary> /// Represents a record of <see cref="OutputStream"/> as defined in the database. /// </summary> public class OutputStream : DataModelBase { #region [ Members ] private Guid m_nodeID; private int m_ID; private string m_acronym; private string m_name; private OutputProtocol m_type = OutputProtocol.IEEE_C37_118_2005; private string m_connectionString; private int m_idCode; private string m_commandChannel; private string m_dataChannel; private bool m_autoPublishConfigFrame; private bool m_autoStartDataChannel; private int m_nominalFrequency; private int m_framesPerSecond; private double m_lagTime; private double m_leadTime; private bool m_useLocalClockAsRealTime; private bool m_allowSortsByArrival; private int m_loadOrder; private bool m_enabled; private bool m_ignoreBadTimeStamps; private int m_timeResolution; private bool m_allowPreemptivePublishing; private string m_downsamplingMethod; private string m_dataFormat; private string m_coordinateFormat; private int m_currentScalingValue; private int m_voltageScalingValue; private int m_analogScalingValue; private int m_digitalMaskValue; private bool m_performTimestampReasonabilityCheck; private bool m_roundToNearestTimestamp; private string m_mirroringSourceDevice = ""; // ReSharper disable once MemberInitializerValueIgnored // Assign initial changed state to true before calling base class constructor call to prevent unintended updates during default value initialization private bool m_autoPublishConfigFrameChangedByUser = true; // Called 1st #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="OutputStream"/>. /// </summary> public OutputStream() : base(false) // Called 2nd { // Post base class constructor call, reset changed state value back to false m_autoPublishConfigFrameChangedByUser = false; // Called 3rd try { // Set default lead/lag time settings to those used by manager screens object lagTimeValue = IsolatedStorageManager.ReadFromIsolatedStorage("LagTime"); if (lagTimeValue is not null && double.TryParse(lagTimeValue.ToString(), out double lagTime) && lagTime > 0.0D) m_lagTime = lagTime; object leadTimeValue = IsolatedStorageManager.ReadFromIsolatedStorage("LeadTime"); if (leadTimeValue is not null && double.TryParse(leadTimeValue.ToString(), out double leadTime) && leadTime > 0.0D) m_leadTime = leadTime; } catch (Exception ex) { Logger.SwallowException(ex); } } #endregion #region [ Properties ] /// <summary> /// Gets or sets function to call when config frame size calculation should be updated. /// </summary> public Action UpdateConfigFrameSize { get; set; } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s NodeID. /// </summary> public Guid NodeID { get => m_nodeID; set { m_nodeID = value; OnPropertyChanged("NodeID"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s ID. /// </summary> // Field is populated by database via auto-increment and has no screen interaction, so no validation attributes are applied. public int ID { get => m_ID; set { m_ID = value; OnPropertyChanged("ID"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Acronym. /// </summary> [Required(ErrorMessage = "Output stream acronym is a required field, please provide value.")] [StringLength(200, ErrorMessage = "Output stream acronym cannot exceed 200 characters.")] [AcronymValidation] public string Acronym { get => m_acronym; set { m_acronym = value; OnPropertyChanged("Acronym"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Name. /// </summary> [StringLength(200, ErrorMessage = "Output stream name cannot exceed 200 characters.")] public string Name { get => m_name; set { m_name = value; OnPropertyChanged("Name"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s output protocol type. /// </summary> [Required(ErrorMessage = "Output stream type is a required, please provide a value.")] public OutputProtocol Type { get => m_type; set { const string ConfigTypeKey = nameof(C37Concentrator.TargetConfigurationType); m_type = value; Dictionary<string, string> settings = ConnectionString?.ParseKeyValuePairs() ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); switch (m_type) { case OutputProtocol.IEEE_C37_118_2011: settings[ConfigTypeKey] = DraftRevision.Std2011.ToString(); break; case OutputProtocol.IEEE_C37_118_2005: settings[ConfigTypeKey] = DraftRevision.Std2005.ToString(); break; default: settings.Remove(ConfigTypeKey); break; } ConnectionString = settings.JoinKeyValuePairs(); OnPropertyChanged("Type"); UpdateConfigFrameSize?.Invoke(); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s ConnectionString. /// </summary> [DefaultValue("addPhaseLabelSuffix=false; replaceWithSpaceChar=_")] public string ConnectionString { get => m_connectionString; set { Dictionary<string, string> settings = value.ParseKeyValuePairs(); if (settings.TryGetValue(nameof(RoundToNearestTimestamp), out string setting)) { RoundToNearestTimestamp = setting.ParseBoolean(); settings.Remove(nameof(RoundToNearestTimestamp)); m_connectionString = settings.JoinKeyValuePairs(); } else { m_connectionString = value; } OnPropertyChanged("ConnectionString"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s IDCode. /// </summary> [Required(ErrorMessage = "Output stream IDCode is a required field, please provide a value.")] public int IDCode { get => m_idCode; set { m_idCode = value; OnPropertyChanged("IDCode"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s CommandChannel. /// </summary> public string CommandChannel { get => m_commandChannel; set { m_commandChannel = value; SetDefaultAutoPublishConfigFrameState(); OnPropertyChanged("CommandChannel"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s DataChannel. /// </summary> public string DataChannel { get => m_dataChannel; set { m_dataChannel = value; SetDefaultAutoPublishConfigFrameState(); OnPropertyChanged("DataChannel"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s AutoPublishConfigFrame flag. /// </summary> [Required(ErrorMessage = "Output stream auto publish config frame is a required field, please provide a value.")] [DefaultValue(false)] public bool AutoPublishConfigFrame { get => m_autoPublishConfigFrame; set { m_autoPublishConfigFrame = value; m_autoPublishConfigFrameChangedByUser = true; OnPropertyChanged("AutoPublishConfigFrame"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s AutoStartDataChannel flag. /// </summary> [Required(ErrorMessage = "Output stream auto start data channel is a required field, please provide a value.")] [DefaultValue(true)] public bool AutoStartDataChannel { get => m_autoStartDataChannel; set { m_autoStartDataChannel = value; OnPropertyChanged("AutoStartDataChannel"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Nominal Frequency. /// </summary> [Required(ErrorMessage = "Output stream nominal frequency is a required field, please provide a value.")] [DefaultValue(60)] public int NominalFrequency { get => m_nominalFrequency; set { m_nominalFrequency = value; OnPropertyChanged("NominalFrequency"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s Frames Per Second. /// </summary> [Required(ErrorMessage = "Output stream frames per second is a required field, please provide a value.")] [DefaultValue(30)] public int FramesPerSecond { get => m_framesPerSecond; set { m_framesPerSecond = value; OnPropertyChanged("FramesPerSecond"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s LagTime. /// </summary> [Required(ErrorMessage = "Output stream lag time is a required field, please provide a value.")] [DefaultValue(3.0)] public double LagTime { get => m_lagTime; set { m_lagTime = value; OnPropertyChanged("LagTime"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s LeadTime. /// </summary> [Required(ErrorMessage = "Output stream lead time is a required field, please provide a value.")] [DefaultValue(1.0)] public double LeadTime { get => m_leadTime; set { m_leadTime = value; OnPropertyChanged("LeadTime"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s UseLocalClockAsRealTime flag. /// </summary> [Required(ErrorMessage = "Output stream use local clock as real-time is a required field, please provide a value.")] [DefaultValue(false)] public bool UseLocalClockAsRealTime { get => m_useLocalClockAsRealTime; set { m_useLocalClockAsRealTime = value; OnPropertyChanged("UseLocalClockAsRealTime"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s AllowSortsByArrival flag. /// </summary> [Required(ErrorMessage = "Output stream allow sorts by arrival is a required field, please provide a value.")] [DefaultValue(true)] public bool AllowSortsByArrival { get => m_allowSortsByArrival; set { m_allowSortsByArrival = value; OnPropertyChanged("AllowSortsByArrival"); } } /// <summary> /// Gets or sets <see cref="OutputStream"/>'s LoadOrder. /// </summary> [Required(ErrorMessage = "Output stream load order is a required field, please provide a value.")] [DefaultValue(0)] public int LoadOrder {