Jump to content

C# WPF program question....

Go to solution Solved by Guest,

A concept several more experienced programmers on the forum told me is to write code that should be self documenting. 

 

For instance, your variable _currentTime doesn’t need a comment saying it triggers every time as it should be expected to have the most up to date time in the program. 

 

You call a method called dlg.ShowDialog() with a comment saying “show dialog box.” 

The method name does one thing. It shows a dialogue box. Things like the above don’t need to be commented because anything ending in () is a method & every method should do 1 thing. 

 

I reserve comments for complicated things. IE some sort of mathematics forumula. 

I won’t comment addition, but if I use the quadratic formula, at the very least I’ll put a comment saying “quadratic formula.” At best I’ll explain the formula. 

 

This could all depend on your teacher. I’ve gotten renouned from my teachers for saying “using self documenting code...” as a lot of code doesn’t need comments. It’s generally expected that someone reading your code will understand both the language & English. 

Your use of summaries is liked by me as it explains how to use methods. Saves me the time of having to research the documentation if there even is any if I need to extend your code. 

Hey guys just looking for feedback on my commenting. Its for a school project so just wondering if any more comments are needed or if you'd do anything different.

namespace Dataset.App.Wpf
{
    public class MainWindowViewModel : ViewModelBase
    {
        private Timer _currentTime; // Timer object to trigger every second
        private int _labelCount; // Count to cycling the label display

        public MainWindowViewModel()
        {
            StartCurrentTime(); // start timer

            //populate offset list for user selection
            var units = new List<OffsetUnit>();
            foreach (OffsetUnit item in Enum.GetValues(typeof(OffsetUnit)))
            {
                units.Add(item);
            }
            OffsetUnits = units.ToList();
            SelectedOffsetUnit = OffsetUnit.Hour; // Select default offset unit as Hour
        }

        

        /// <summary>
        /// Trigger when browse button is clicked
        /// </summary>
        private RelayCommand _BrowseCommand;
        public ICommand BrowseCommand
        {
            get
            {
                if (_BrowseCommand == null)
                    _BrowseCommand = new RelayCommand(() => OnBrowse());
                return _BrowseCommand;
            }
        }
        /// <summary>
        /// Pop open dialog windows and allow user to select dataset file
        /// </summary>
        private void OnBrowse()
        {
            try
            {
                var openFileDialog = new System.Windows.Forms.OpenFileDialog();
                openFileDialog.Title = "Input file";
                openFileDialog.Multiselect = false;

                var result = openFileDialog.ShowDialog();

                if (result == System.Windows.Forms.DialogResult.OK) // If user click okay on open dialog
                {
                    using (var mystream = openFileDialog.OpenFile()) // try read if file is currently in use, will throw error if file is currently in use
                    {
                        if (mystream != null)
                            FileDirectory = openFileDialog.FileName; // Set file directory to FileDirectory for display on UI
                    }
                    if (string.IsNullOrEmpty(FileDirectory)) // if FileDirectory is empty or null, return
                        return;
                    Datasets = FileFormatHelper.Parse(FileDirectory).ToObservableCollection(); //Parse directory file and assign to dataset
                    if (Datasets.Count == 0) // if dataset parsed with zero count, throw error as file might be invalid format
                    {
                        throw new Exception("There is problem with parsing input file");
                    }
                    foreach (var item in Datasets) //If dataset is valid, set offset unit to each set by user selected offset value
                    {
                        item.PopulateDates(SelectedOffsetUnit);
                    }
                    SelectedDataset = Datasets.FirstOrDefault(); //Select first set as default
                    OnPlot();//trigger plot update
                }
            }
            catch (Exception e) // if any error above show message box
            {
                MessageBox.Show(e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Will trigger when validate button is clicked
        /// </summary>
        private RelayCommand _ValidateCommand;
        public ICommand ValidateCommand
        {
            get
            {
                if (_ValidateCommand == null)
                    _ValidateCommand = new RelayCommand(() => OnValidate());
                return _ValidateCommand;
            }
        }
        private void OnValidate()
        {
            var validatingResult = FileFormatHelper.Validate(FileDirectory); //Parse directory file and perform validation
            if (validatingResult.Item1) // show messagebox base on validation result
            {
                MessageBox.Show("Validation success. No missing datasets", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                MessageBox.Show("Validation Fail. " + validatingResult.Item2, "Failed", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// trigger when generate plot is clicked
        /// </summary>
        private RelayCommand _PlotCommand;
        public ICommand PlotCommand
        {
            get
            {
                if (_PlotCommand == null)
                    _PlotCommand = new RelayCommand(() => OnPlot());
                return _PlotCommand;
            }
        }
        private void OnPlot() //Plot selected dataset
        {
            PopulatePlot(SelectedDataset);
        }

        /// <summary>
        /// Trigger when export button is clicked
        /// </summary>
        private RelayCommand _ExportCommand;
        public ICommand ExportCommand
        {
            get
            {
                if (_ExportCommand == null)
                    _ExportCommand = new RelayCommand(() => OnExport());
                return _ExportCommand;
            }
        }
        /// <summary>
        /// popup savefiledialog and prompt user with export file option
        /// </summary>
        private void OnExport()
        {

            var dlg = new System.Windows.Forms.SaveFileDialog();
            dlg.Title = "Export Dataset";
            dlg.DefaultExt = ".txt";
            dlg.Filter = "Text (*.txt)|*.txt|All files (*.*)|*.*"; //filter files by extension
            dlg.FileName = "Dataset";
            var result = dlg.ShowDialog(); //Show dialog
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                if (string.IsNullOrEmpty(dlg.FileName))
                    return;
                var exportText = FileFormatHelper.Export(this.Datasets.ToList()); //get export string from file format helper
                File.WriteAllText(dlg.FileName, exportText); //Write file
                Process.Start(dlg.FileName); //Open file
            }
        }


        /// <summary>
        /// trigger when exit is clicked
        /// </summary>
        private RelayCommand _ExitCommand;
        public ICommand ExitCommand
        {
            get
            {
                if (_ExitCommand == null)
                    _ExitCommand = new RelayCommand(() => OnExit());
                return _ExitCommand;
            }
        }
        private void OnExit()
        {
            System.Windows.Application.Current.Shutdown();
        }

        /// <summary>
        /// Initiate timer object and refresh every 1000 millisecond
        /// </summary>
        private void StartCurrentTime()
        {
            _currentTime = new Timer();
            _currentTime.Interval = 1000;
            // Hook up the Elapsed event for the timer.
            _currentTime.Elapsed += OnCurrentTimeEvent;
            // Have the timer fire repeated events (true is the default)
            _currentTime.AutoReset = true;
            // Start the timer
            _currentTime.Enabled = true;
            _currentTime.Start();
        }

        /// <summary>
        /// Elapsed event to trigger update of current time. If dataset is loaded also update cycling of the label
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnCurrentTimeEvent(Object source, System.Timers.ElapsedEventArgs e)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                CurrentTime = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");
                if (Datasets != null && Datasets.Count > 0)
                {
                    var currentIndex = _labelCount % Datasets.Count;
                    var dataset = Datasets[currentIndex];
                    DatasetTimerInfo = string.Format("Dataset: {0}, Creation Time: {1}", dataset.Title, dataset.RecordingDateTime.ToString("dd/MM/yyyy HH:mm:ss"));
                    _labelCount++;
                }
            });
        }

        /// <summary>
        /// Populating dataset plot
        /// </summary>
        /// <param name="setName">Name of dataset to plot, if missing method is return with no action</param>
        public void PopulatePlot(string setName)
        {
            var ds = Datasets.FirstOrDefault(x => x.Title == setName);
            if (ds != null)
                PopulatePlot(ds);
        }

        /// <summary>
        /// Populating dataset plot
        /// </summary>
        /// <param name="ds">dataset to plot</param>
        public void PopulatePlot(DatasetObject ds)
        {
            if (ds == null)
                return;
            Model = ds.GetPlotModel(SelectedPlotOption);
        }

        /// <summary>
        /// List of offset unit for user selection
        /// </summary>
        private List<OffsetUnit> _OffsetUnits;
        public List<OffsetUnit> OffsetUnits
        {
            get { return _OffsetUnits; }
            set
            {
                if (value == _OffsetUnits)
                    return;
                _OffsetUnits = value;
                RaisePropertyChanged("OffsetUnits");
            }
        }

        /// <summary>
        /// Current selection of offset unit
        /// </summary>
        private OffsetUnit _SelectedOffsetUnit;
        public OffsetUnit SelectedOffsetUnit
        {
            get { return _SelectedOffsetUnit; }
            set
            {
                if (value == _SelectedOffsetUnit)
                    return;
                _SelectedOffsetUnit = value;
                if (Datasets != null)
                    foreach (var item in Datasets)
                    {
                        item.PopulateDates(SelectedOffsetUnit);
                    }
                OnPlot();
                RaisePropertyChanged("SelectedOffsetUnit");
            }
        }

        /// <summary>
        /// Current user selected plot type
        /// </summary>
        private PlotOption _SelectedPlotOption;
        public PlotOption SelectedPlotOption
        {
            get { return _SelectedPlotOption; }
            set
            {
                if (value == _SelectedPlotOption)
                    return;
                _SelectedPlotOption = value;
                OnPlot();
                RaisePropertyChanged("SelectedPlotOption");
            }
        }

        /// <summary>
        /// Time label display on UI
        /// </summary>
        private string _CurrentTime;
        public string CurrentTime
        {
            get { return _CurrentTime; }
            set
            {
                if (value == _CurrentTime)
                    return;
                _CurrentTime = value;
                RaisePropertyChanged("CurrentTime");
            }
        }

        /// <summary>
        /// Plot Model to be binded with oxyplot graph
        /// </summary>
        private PlotModel _Model;
        public PlotModel Model
        {
            get { return _Model; }
            set
            {
                if (value == _Model)
                    return;
                _Model = value;
                RaisePropertyChanged("Model");
            }
        }


        /// <summary>
        /// Label of cycling dataset display on UI
        /// </summary>
        private string _DatasetTimerInfo;
        public string DatasetTimerInfo
        {
            get { return _DatasetTimerInfo; }
            set
            {
                if (value == _DatasetTimerInfo)
                    return;
                _DatasetTimerInfo = value;
                RaisePropertyChanged("DatasetTimerInfo");
            }
        }

        /// <summary>
        /// Current selection of dataset
        /// </summary>
        private DatasetObject _SelectedDataset;
        public DatasetObject SelectedDataset
        {
            get { return _SelectedDataset; }
            set
            {
                if (value == _SelectedDataset)
                    return;
                _SelectedDataset = value;
                RaisePropertyChanged("SelectedDataset");
            }
        }

        /// <summary>
        /// List of current imported datasets
        /// </summary>
        private ObservableCollection<DatasetObject> _Datasets;
        public ObservableCollection<DatasetObject> Datasets
        {
            get { return _Datasets; }
            set
            {
                if (value == _Datasets)
                    return;
                _Datasets = value;
                RaisePropertyChanged("Datasets");
            }
        }


        /// <summary>
        /// Current selected importfile directory
        /// </summary>
        private string _FileDirectory;
        public string FileDirectory
        {
            get { return _FileDirectory; }
            set
            {
                if (value == _FileDirectory)
                    return;
                _FileDirectory = value;
                RaisePropertyChanged("FileDirectory");
            }
        }
    }

    public class DatasetObject : ObservableObject
    {

        /// <summary>
        /// if filtering is enabled
        /// </summary>
        private bool _IsFiltering;
        public bool IsFiltering
        {
            get { return _IsFiltering; }
            set
            {
                if (value == _IsFiltering)
                    return;
                _IsFiltering = value;
                RaisePropertyChanged("IsFiltering");
            }
        }

        //These properties assist with filtering if filtering is perform by value instead of date
        /// <summary>
        /// Is filter by value lowerbound
        /// </summary>
        private bool _IsLowerBound;
        public bool IsLowerBound
        {
            get { return _IsLowerBound; }
            set
            {
                if (value == _IsLowerBound)
                    return;
                _IsLowerBound = value;
                RaisePropertyChanged("IsLowerBound");
            }
        }

        /// <summary>
        /// Is filter by value upperbound
        /// </summary>
        private bool _IsUpperBound;
        public bool IsUpperBound
        {
            get { return _IsUpperBound; }
            set
            {
                if (value == _IsUpperBound)
                    return;
                _IsUpperBound = value;
                RaisePropertyChanged("IsUpperBound");
            }
        }

        /// <summary>
        /// value of lower bound
        /// </summary>
        private double _LowerBoundValue;
        public double LowerBoundValue
        {
            get { return _LowerBoundValue; }
            set
            {
                if (value == _LowerBoundValue)
                    return;
                _LowerBoundValue = value;
                RaisePropertyChanged("LowerBoundValue");
            }
        }


        /// <summary>
        /// value of upper bound
        /// </summary>
        private double _UpperBoundValue;
        public double UpperBoundValue
        {
            get { return _UpperBoundValue; }
            set
            {
                if (value == _UpperBoundValue)
                    return;
                _UpperBoundValue = value;
                RaisePropertyChanged("UpperBoundValue");
            }
        }

        /// <summary>
        /// current selection of filtering date
        /// </summary>
        private DateTime _SelectedFilteredDate;
        public DateTime SelectedFilteredDate
        {
            get { return _SelectedFilteredDate; }
            set
            {
                if (value == _SelectedFilteredDate)
                    return;
                _SelectedFilteredDate = value;
                RaisePropertyChanged("SelectedFilteredDate");
            }
        }

        /// <summary>
        /// list of dates for user to choose filtering date
        /// </summary>
        private List<DateTime> _Dates;
        public List<DateTime> Dates
        {
            get { return _Dates; }
            set
            {
                if (value == _Dates)
                    return;
                _Dates = value;
                RaisePropertyChanged("Dates");
            }
        }

        /// <summary>
        /// Name of the dataset
        /// </summary>
        private string _Title;
        public string Title
        {
            get { return _Title; }
            set
            {
                if (value == _Title)
                    return;
                _Title = value;
                RaisePropertyChanged("Title");
            }
        }

        /// <summary>
        /// Initial recoring time
        /// </summary>
        private DateTime _RecordingDateTime;
        public DateTime RecordingDateTime
        {
            get { return _RecordingDateTime; }
            set
            {
                if (value == _RecordingDateTime)
                    return;
                _RecordingDateTime = value;
                RaisePropertyChanged("RecordingDateTime");
            }
        }

        /// <summary>
        /// offset value
        /// </summary>
        private double _SampleOffset;
        public double SampleOffset
        {
            get { return _SampleOffset; }
            set
            {
                if (value == _SampleOffset)
                    return;
                _SampleOffset = value;
                RaisePropertyChanged("SampleOffset");
            }
        }

        /// <summary>
        /// data of the set
        /// </summary>
        private List<double> _Datas;
        public List<double> Datas
        {
            get { return _Datas; }
            set
            {
                if (value == _Datas)
                    return;
                _Datas = value;
                RaisePropertyChanged("Datas");
            }
        }

        /// <summary>
        /// Get PlotModel to be bind to oxyplot
        /// </summary>
        /// <param name="pltOption"></param>
        /// <returns></returns>
        public PlotModel GetPlotModel(PlotOption pltOption)//, bool resetOffset
        {
            //get boundary filter by value
            var bound = GetBoundFilter();
            if (!double.IsNaN(bound.Item2) && bound.Item1 > bound.Item2) // check  if user input boundary is valid
            {
                MessageBox.Show("Lower bound cannot be greater than upper bound", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return null;
            }
            var datasTuples = ProcessLowerUpperBoundSeries(bound); //Process filter by value, not active by default
            datasTuples = ProcessPlotOptionSeries(datasTuples, pltOption); // Process series base on user plot type selection


            var tmpModel = new PlotModel { Title = Title, LegendPlacement = LegendPlacement.Outside }; //set title for plot and placement of legend
            var series = new LineSeries { Title = Title, MarkerType = MarkerType.Circle }; // set title for series and marker type

            var dateTimeAxis = new DateTimeAxis(); // set xaxis to date
            dateTimeAxis.Position = AxisPosition.Bottom;
            dateTimeAxis.Key = "dateTimeAxis";
            tmpModel.Axes.Add(dateTimeAxis); // add axis object to plot

            for (int i = 0; i < datasTuples.Count; i++)
            {
                if (datasTuples.Item1 >= GetFilterDate()) //perform filter by date
                    series.Points.Add(new DataPoint(DateTimeAxis.ToDouble(datasTuples.Item1), datasTuples.Item2)); //add plot point to graph
            }
            tmpModel.Series.Add(series); //add series to graph
            return tmpModel;
        }

        /// <summary>
        /// Get filtered serie
        /// </summary>
        /// <returns></returns>
        public List<Tuple<DateTime, double>> GetFilteredSeries()
        {
            var serie = ProcessLowerUpperBoundSeries(GetBoundFilter()); //Process filter by value, filter is not active by default
            return serie.Where(x=>x.Item1 >= GetFilterDate()).ToList(); // process filter by date
        }
        /// <summary>
        /// Perform filtering of data series with value boundary
        /// </summary>
        /// <param name="LowerUpperBound">boundary object Tuple<double,double></param>
        /// <returns></returns>
        private List<Tuple<DateTime, double>> ProcessLowerUpperBoundSeries(Tuple<double, double> LowerUpperBound)
        {
            var lowerbound = !double.IsNaN(LowerUpperBound.Item1) ? LowerUpperBound.Item1 : double.NegativeInfinity; // if lower bound not set to negative infinit
            var upperbound = !double.IsNaN(LowerUpperBound.Item2) ? LowerUpperBound.Item2 : double.PositiveInfinity; // if lower bound not set to positive infinit
            var datasTuples = new List<Tuple<DateTime, double>>();
            for (int i = 0; i < Datas.Count; i++)
            {
                if (Datas >= lowerbound && Datas <= upperbound) // If data pass the bound add to list
                {
                    var offsetTime = Dates;
                    datasTuples.Add(new Tuple<DateTime, double>(offsetTime, Datas));
                }
            }
            return datasTuples; // return filtered value
        }

        /// <summary>
        /// Processing series point based on user selection
        /// </summary>
        /// <param name="serie">Original serie</param>
        /// <param name="pltOption">Selected Option</param>
        /// <returns></returns>
        private List<Tuple<DateTime,double>> ProcessPlotOptionSeries(List<Tuple<DateTime,double>> serie,PlotOption pltOption)
        {
            switch (pltOption)
            {
                case PlotOption.Normal:
                    return serie;
                case PlotOption.ThreePointsMovingAverage:
                    return ThreePointMovingAverage.Process(serie);
                case PlotOption.WhiteNoise:
                    return WhiteNoiseHelper.Process(serie);
                case PlotOption.Cumulative:
                    return CumulativeHelper.Process(serie);
                default:
                    return new List<Tuple<DateTime, double>>();
            }
        }

        /// <summary>
        /// Calculating offset from recording date and offset index with unit of offset
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="i"></param>
        /// <param name="unit"></param>
        /// <returns></returns>
        private DateTime CalculatingOffset(DateTime dt, int i, OffsetUnit unit)
        {
            switch (unit)
            {
                case OffsetUnit.Second:
                    return dt.AddSeconds(SampleOffset * i);
                case OffsetUnit.Hour:
                    return dt.AddHours(SampleOffset * i);
                case OffsetUnit.Day:
                    return dt.AddDays(SampleOffset * i);
                case OffsetUnit.Month:
                    return dt.AddMonths(Convert.ToInt32(SampleOffset) * i);
                default:
                    return dt;
            }
        }

        /// <summary>
        /// repopulate list filter selection base on new offset unit select
        /// </summary>
        /// <param name="unit"></param>
        public void PopulateDates(OffsetUnit unit)
        {
            var result = new List<DateTime>();
            for (int i = 0; i < Datas.Count; i++)
            {
                result.Add(CalculatingOffset(RecordingDateTime, i, unit));
            }
            Dates = result.ToList();
            SelectedFilteredDate = Dates.FirstOrDefault(); //select first of list as default
        }

        /// <summary>
        /// Get bound value if filter is perform by value, inactive by default
        /// </summary>
        /// <returns></returns>
        private Tuple<double, double> GetBoundFilter()
        {
            var lowerValue = double.NaN;
            var upperValue = double.NaN;
            if (IsFiltering)
            {
                if (IsLowerBound)
                    lowerValue = LowerBoundValue;
                if (IsUpperBound)
                    upperValue = UpperBoundValue;
            }
            return new Tuple<double, double>(lowerValue, upperValue);
        }

        /// <summary>
        /// Get filter date value, if not active date filter will return date minvalue
        /// </summary>
        /// <returns></returns>
        private DateTime GetFilterDate()
        {
            return IsFiltering ? SelectedFilteredDate : DateTime.MinValue;
        }
    }

    /// <summary>
    /// Enum for plot type selection
    /// </summary>
    public enum PlotOption
    {
        Normal,
        ThreePointsMovingAverage,
        WhiteNoise,
        Cumulative,
    }

    /// <summary>
    /// Offset unit for selection
    /// </summary>
    public enum OffsetUnit
    {
        Second,
        Hour,
        Day,
        Month,
    }
}

  

 

Link to comment
Share on other sites

Link to post
Share on other sites

@Forenman

 

 

If you need to post code, please follow the posting guidelines and use the code tag ;

image.png.b0e0dc48f3254f49655980b1bbc5be30.png

 

 

Your thread was corrected for you.

Edited by wkdpaul

If you need help with your forum account, please use the Forum Support form !

Link to comment
Share on other sites

Link to post
Share on other sites

In reality, I try to let me code speak for itself. With good named classes, methods and variables. 

 

In C# you could use #REGION and #ENDREGION for commenting.

 

#region MyClass definition  
public class MyClass   
{  
    static void Main()   
    {  
    }  
}  
#endregion 

 

Link to comment
Share on other sites

Link to post
Share on other sites

A concept several more experienced programmers on the forum told me is to write code that should be self documenting. 

 

For instance, your variable _currentTime doesn’t need a comment saying it triggers every time as it should be expected to have the most up to date time in the program. 

 

You call a method called dlg.ShowDialog() with a comment saying “show dialog box.” 

The method name does one thing. It shows a dialogue box. Things like the above don’t need to be commented because anything ending in () is a method & every method should do 1 thing. 

 

I reserve comments for complicated things. IE some sort of mathematics forumula. 

I won’t comment addition, but if I use the quadratic formula, at the very least I’ll put a comment saying “quadratic formula.” At best I’ll explain the formula. 

 

This could all depend on your teacher. I’ve gotten renouned from my teachers for saying “using self documenting code...” as a lot of code doesn’t need comments. It’s generally expected that someone reading your code will understand both the language & English. 

Your use of summaries is liked by me as it explains how to use methods. Saves me the time of having to research the documentation if there even is any if I need to extend your code. 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×