/// <summary>
        /// A method triggered by the DataCleared event that clears all point information
        /// </summary>
        /// <param name="sender">The solver that sent the event</param>
        /// <param name="args">The event arguments</param>
        private void OnDataCleared(object sender, EventArgs args)
        {
            AddedOrder.Clear();
            PlotSeries.Points.Clear();

            PlotInfo.InvalidatePlot(true);
        }
        /// <summary>
        /// A method triggered by the CityAdded event that adds the point to the graph
        /// </summary>
        /// <param name="sender">The solver sending the message</param>
        /// <param name="args">The information about the city added</param>
        private void OnCityAdded(object sender, CityAddedEventArgs args)
        {
            // Add to the AddedOrder list to keep track of order
            AddedOrder.Add(args.AddedCity);

            // Plot the new point on the graph
            var point = new DataPoint(args.AddedCity.XPosition, args.AddedCity.YPosition);

            PlotSeries.Points.Insert(args.Index, point);

            // Update the UI
            NotifyOfPropertyChange(nameof(AddedOrder));
            PlotInfo.InvalidatePlot(true);
        }
        /// <summary>
        /// A method that reads the cities from the current file
        /// </summary>
        private void ReadFile()
        {
            CitySeries.Points.Clear();
            Cities.Clear();
            // Makes sure the file is valid
            if (CurrentFile != null && !CurrentFile.Exists)
            {
                MessageBox.Show("There is no valid file selected", "No Valid File",
                                MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            StreamReader reader = new StreamReader(CurrentFile.FullName);

            // Skip the first four lines
            for (int x = 0; x < 4; x++)
            {
                reader.ReadLine();
            }

            // Get the number of destinations
            var temp      = reader.ReadLine().Split(' ');
            int cityCount = int.Parse(temp[1]);

            // Skip two more lines
            for (int y = 0; y < 2; y++)
            {
                reader.ReadLine();
            }

            // Read the data for each city
            for (int z = 0; z < cityCount; z++)
            {
                temp = reader.ReadLine().Split(' ');
                var city = new City(int.Parse(temp[0]),
                                    double.Parse(temp[1]),
                                    double.Parse(temp[2]));
                // Add the city to the list
                Cities.Add(city);

                // Add the city to the graph
                CitySeries.Points.Add(new ScatterPoint(city.XPosition, city.YPosition));
            }

            PlotInfo.InvalidatePlot(true);
            OnDataCleared(this, new EventArgs());
            GSolver.OrderData(Cities);
        }
        /// <summary>
        /// A method triggered by the NewBestTrip event that updates the new best path
        /// </summary>
        /// <param name="sender">The solver that sent the event</param>
        /// <param name="args">The event arguments</param>
        private void OnNewBestTrip(object sender, BestFoundEventArgs args)
        {
            PathSeries.Points.Clear();

            foreach (City point in args.NewBest.Stops)
            {
                PathSeries.Points.Add(new DataPoint(point.XPosition, point.YPosition));
            }

            ChangeSeries.Points.Add(new DataPoint(args.Generation, 1 / (args.NewBest.Fitness) + 1));

            BestDistance = (int)args.NewBest.GetDistance();

            NotifyOfPropertyChange(nameof(BestDistance));
            PlotInfo.InvalidatePlot(true);
            ChangeInfo.InvalidatePlot(true);
        }