using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Win32; using Microsoft.WindowsAPICodePack.Dialogs; using Tango.Core.Commands; using Tango.CSV; using Tango.DispenserAnalyzer.UI.Models; using Tango.SharedUI; using System.Collections.ObjectModel; using System.IO; using System.Windows.Input; using Tango.DispenserAnalyzer.UI.Analysis; using System.Windows; using System.Windows.Threading; using OxyPlot; using OxyPlot.Wpf; using OxyPlot.Annotations; using System.Windows.Media; using System.Diagnostics; using System.Windows.Documents; using System.Windows.Controls; using System.Windows.Xps; using System.Windows.Xps.Packaging; using System.Windows.Media.Imaging; using PdfSharp; using OxyPlot.Reporting; using Tango.Documents; using Tango.DispenserAnalyzer.UI.View; using Tango.Core.Helpers; using Tango.DispenserAnalyzer.UI.ExcelModel; using Tango.DispenserAnalyzer.UI.Analyzers; using static Tango.DispenserAnalyzer.UI.Analyzers.FlowAnalyser; using System.Text.RegularExpressions; using System.Reflection; using System.Globalization; namespace Tango.DispenserAnalyzer.UI.ViewModels { public class MainWindowVM: ViewModel { private const string FILE_EXTENSION = ".pdf"; private string _settingsFilepath = ""; #region Properties public Plot PlotControl { get; set; } /// /// Gets or sets the results panel. Using to save all results in xps file /// public System.Windows.Controls.ItemsControl ResultsPanel { get; set; } private string _openFilePath; public string OpenFilePath { get { return _openFilePath; } set { if(value != null && _openFilePath != value) { _openFilePath = value; OnSelectedFileChanged(); RaisePropertyChangedAuto(); GenerateCommand.RaiseCanExecuteChanged(); } } } private string _filename; public string FileName { get { return _filename; } set { _filename = value; RaisePropertyChangedAuto(); RaisePropertyChanged("ButtonName"); } } public string ButtonName { get { return "Generate result for " + FileName; } } private string _testName = ""; public string TestName { get { return _testName.ToUpper() + " TEST"; } set { _testName = value; RaisePropertyChangedAuto(); } } private IList _points; /// /// Binding to ItemsSource of line chart. /// public IList Points { get { return _points; } set { _points = value; RaisePropertyChangedAuto(); } } private int _step; public int XStep { get { return _step; } set { _step = value; RaisePropertyChangedAuto(); } } private double _from; /// /// From use to binding to bottom axis min value /// public double From { get { return _from; } set { _from = value; RaisePropertyChangedAuto(); } } private double _to; /// /// To use to binding to bottom axis max value /// public double To { get { return _to; } set { _to = value; RaisePropertyChangedAuto(); } } private string _titleAxisBottom; public string TitleAxisBottom { get { return _titleAxisBottom; } set { _titleAxisBottom = value; RaisePropertyChangedAuto(); } } private string _titleAxisLeft; public string TitleAxisLeft { get { return _titleAxisLeft; } set { _titleAxisLeft = value; RaisePropertyChangedAuto(); } } private bool _isRunning; /// /// Gets or sets a value indicating whether this instance is running. /// public bool IsRunning { get { return _isRunning; } set { _isRunning = value; RaisePropertyChangedAuto(); } } private ObservableCollection _analyzerResults; public ObservableCollection AnalyzerResults { get { return _analyzerResults; } set { _analyzerResults = value; RaisePropertyChangedAuto(); } } public Func YFormatter { get; set; } private Visibility _isCompareVisible; public Visibility IsCompareVisible { get { return _isCompareVisible; } set { _isCompareVisible = value; RaisePropertyChangedAuto(); } } private bool _addToComare; public bool AddToComare { get { return _addToComare; } set { _addToComare = value; OnAddToCompareResults(value); RaisePropertyChangedAuto(); } } private string _compareResText1; public string CompareResText1 { get { if (String.IsNullOrEmpty(_compareResText1)) return "Empty"; return _compareResText1; } set { _compareResText1 = value; RaisePropertyChangedAuto(); } } private string _compareResText2; public string CompareResText2 { get { if (String.IsNullOrEmpty(_compareResText2)) return "Empty"; return _compareResText2; } set { _compareResText2 = value; RaisePropertyChangedAuto(); } } private bool _isAddedRes1; public bool IsAddedRes1 { get { return _isAddedRes1; } set { _isAddedRes1 = value; RaisePropertyChangedAuto(); } } private bool _isAddedRes2; public bool IsAddedRes2 { get { return _isAddedRes2; } set { _isAddedRes2 = value; RaisePropertyChangedAuto(); } } private ObservableCollection _resultsToCompare; public ObservableCollection ResultsToCompare { get { return _resultsToCompare; } set { _resultsToCompare = value; } } #endregion #region Commands public RelayCommand OpenCSVFileCommand { get; set; } public RelayCommand GenerateCommand { get; set; } public RelayCommand OpenSettingWndCommand { get; set; } public RelayCommand CompareCommand { get; set; } public RelayCommand SaveExelCommand { get; set; } #endregion public MainWindowVM() { ResultsToCompare = new ObservableCollection(); OpenCSVFileCommand = new RelayCommand(OpenCSVFile); GenerateCommand = new RelayCommand(Generate, CanGenerate); OpenSettingWndCommand = new RelayCommand(OpenSettingWnd); CompareCommand = new RelayCommand(Compareresults, CanCompareresults); SaveExelCommand = new RelayCommand(SaveExel, CanSaveExel); YFormatter = value => value.ToString(); _from = 0; _to = 1; XStep = 1; AnalyzerResults = new ObservableCollection(); _isRunning = false; TitleAxisBottom = ""; TitleAxisLeft = ""; this.Points = new List(); IsCompareVisible = Visibility.Collapsed; IsAddedRes1 = IsAddedRes2 = false; InitUserSettings(); } #region Settings public void InitUserSettings() { string folderPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "DispenserAnalyzer"); Directory.CreateDirectory(folderPath); _settingsFilepath = System.IO.Path.Combine(folderPath, "Settings.json"); try { Settings.DeserializeSettings(_settingsFilepath); } catch (IOException ex) { MessageBox.Show("Warning: " + ex.Message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); } } public void OpenSettingWnd() { SettingsWnd settings = new SettingsWnd(); settings.Owner = System.Windows.Application.Current.MainWindow; if(true == settings.ShowDialog()) { Dictionary changes = settings.GetChanges(); foreach (KeyValuePair entry in changes) { Settings.SetValueByName(entry.Key, entry.Value); } try { Settings.SerializeSettings(_settingsFilepath); } catch (IOException ex) { MessageBox.Show("Warning: " + ex.Message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); } } } private void ClearResults() { IsCompareVisible = Visibility.Collapsed; _addToComare = false; RaisePropertyChanged("AddToComare"); Points.Clear(); AnalyzerResults.Clear(); TestName = ""; foreach (var ax in PlotControl.Axes) { ax.Maximum = ax.Minimum = Double.NaN; PlotControl.ResetAllAxes(); } PlotControl.Annotations.Clear(); PlotControl.InvalidatePlot(true); } #endregion #region Read File private void OpenCSVFile() { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "CSV Files|*.csv"; if (dlg.ShowDialog().Value) { try { OpenFilePath = dlg.FileName; } catch (Exception ex) { MessageBox.Show("An error occurred while trying to import the CSV file. " + ex.Message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); } } } protected virtual bool IsFileLocked(string filePath) { FileStream stream = null; try { stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None); } catch (IOException ex) { MessageBox.Show("Warning: " + ex.Message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); return true; } finally { if (stream != null) stream.Close(); } return false; } private void OnSelectedFileChanged() { ClearResults(); if(File.Exists(OpenFilePath)) { FileHelper.OpenFilePath = OpenFilePath; FileName = Path.GetFileName(OpenFilePath); } SaveExelCommand.RaiseCanExecuteChanged(); } #endregion #region Generate public bool CanGenerate() { var value = (OpenFilePath != null && OpenFilePath.Length != 0 && File.Exists(OpenFilePath)); return (OpenFilePath!= null && OpenFilePath.Length != 0 && File.Exists(OpenFilePath)); } /// /// Generates all results. /// public async void Generate() { if (false == File.Exists(OpenFilePath) || IsFileLocked(OpenFilePath)) return; ClearResults(); var analyzer = AnalysisService.GetAnalyzer(OpenFilePath); if (analyzer == null) return; IsRunning = true; AnalyzerAttribute[] attr = analyzer.GetType().GetCustomAttributes(typeof(AnalyzerAttribute), true); if (attr != null && attr.Count() > 0) { TestName = attr[0].Name; } List annotations = new List(); var samples = analyzer.Reader.ReadScvFile(OpenFilePath, annotations); bool showChartAfterProcess = analyzer.ShowChartAfterProcess; if (false == showChartAfterProcess) { analyzer.GetPoints(samples, Points); if (Points.Count == 0) { IsRunning = false; return; } } //visible only for process type IsCompareVisible = analyzer.AvailableCompareResults ? Visibility.Visible : Visibility.Collapsed; annotations.ForEach(x => PlotControl.Annotations.Add(x)); To = 0; From = 0; List res = await analyzer.Process(samples, false); AnalyzerResults = new ObservableCollection(res); if (showChartAfterProcess) { analyzer.GetPoints(samples, Points); if (Points.Count == 0) { IsRunning = false; return; } } _to = Points.Max(x => x.Y); _from = TestName.Contains("sealtest") ? Points.FirstOrDefault(x => x.X == 0).Y : Points.Min(x => x.Y); List titles = analyzer.Reader.GetTitles(OpenFilePath); TitleAxisBottom = titles[0]; TitleAxisLeft = titles[1]; // data.Clear(); _to += 100; RaisePropertyChanged("To"); if (_from != 0) _from -= 100; RaisePropertyChanged("From"); XStep = (int)(Points.Count / 5); IsRunning = false; PlotControl.InvalidatePlot(true); if(analyzer.Reader.PrintResultsToPDFFile()) { await PrintToXpsFile(); } InvalidateRelayCommands(); } /// /// Generates all results from command line and close application. /// public async Task GenerateInBackground(string openFilePath) { OpenFilePath = openFilePath; if (false == File.Exists(OpenFilePath) || IsFileLocked(OpenFilePath)) return; var analyzer = AnalysisService.GetAnalyzer(OpenFilePath); if (analyzer == null) return; AnalyzerAttribute[] attr = analyzer.GetType().GetCustomAttributes(typeof(AnalyzerAttribute), true); if (attr != null && attr.Count() > 0) { TestName = attr[0].Name; } List annotations = new List(); var samples = analyzer.Reader.ReadScvFile(OpenFilePath, annotations); analyzer.GetPoints(samples, Points); if (Points.Count == 0) { return; } List res = await analyzer.Process(samples, true); AnalyzerResults = new ObservableCollection(res); await ExportResultsToTextFile(); } #endregion #region SaveInXps file private async Task PrintToXpsFile() { await Task.Delay(200); try { var resultFile = FileHelper.GetResultFilePath(); if (resultFile.IsNotNullOrEmpty()) { SaveResultsAsXps(resultFile); } } catch(Exception ex) { Debug.WriteLine(ex); } } public void SaveResultsAsXps( string fileName) { var dir = Path.GetDirectoryName(fileName); var name = Path.GetFileNameWithoutExtension(fileName); string fileNameWithoutExtension = Path.Combine(dir, name); ContentControl cc = ResultsPanel.Parent as ContentControl; ResultsPanel.UpdateLayout(); List all_plots = ResultsPanel.FindVisualChildren().ToList(); List plots = new List(); List plotimages = new List(); int index = 0; foreach (var item in all_plots) { var seriesdata = item.Series[0].ItemsSource; item.RaiseEvent(new System.Windows.RoutedEventArgs(OxyPlot.Wpf.PlotView.LoadedEvent)); item.InvalidatePlot(true); if (item.IsMeasureValid && item.ActualHeight > 0) { plots.Add(item); string pngPlotFileName = String.Format($"{fileNameWithoutExtension}_Plottest{index}.png"); File.Delete(pngPlotFileName); System.Windows.Controls.Image plotImage = new System.Windows.Controls.Image(); //print plot to png file - removed 2/07/2020 //using (var stream = File.Open(pngPlotFileName, FileMode.Create, FileAccess.ReadWrite)) { PngExporter exporter = new PngExporter() { Width = (int)item.ActualWidth, Height = (int)item.ActualHeight, Background = OxyColors.White, Resolution = 96 }; //exporter.Export(item.ActualModel, stream); BitmapSource bitmap = exporter.ExportToBitmap(item.ActualModel); plotImage.Source = bitmap; plotImage.UpdateLayout(); var parent = item.Parent; if (parent is Panel) { var plpanel = (Panel)parent; plpanel.Children.Remove(item); plpanel.Children.Add(plotImage); plpanel.UpdateLayout(); } else if (parent is Decorator) { ((Decorator)parent).Child = plotImage; ((Border)parent).UpdateLayout(); } } plotimages.Add(plotImage); index++; } ResultsPanel.UpdateLayout(); } if (cc != null) { cc.Content = null; CreateDoc(fileName, plots, plotimages); cc.Content = ResultsPanel; } } private void CreateDoc( string fileName, List plots, List plotimages) { Dispatcher.CurrentDispatcher.Invoke( DispatcherPriority.Loaded, new Action(() => { var dir = Path.GetDirectoryName(fileName); var name = Path.GetFileNameWithoutExtension(fileName); string fileNameWithoutExtension = Path.Combine(dir, name); Size reportSize = GetReportSize(ResultsPanel); FixedDocument fixedDoc = new FixedDocument(); PageContent pageContent = new PageContent(); FixedPage fixedPage = new FixedPage(); fixedPage.Width = reportSize.Width; fixedPage.Height = reportSize.Height; fixedPage.Children.Add(ResultsPanel); fixedPage.UpdateLayout(); pageContent.BeginInit(); ((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage); pageContent.EndInit(); fixedDoc.Pages.Add(pageContent); InjectData(fixedDoc, AnalyzerResults); ResultsPanel.Measure(reportSize); ResultsPanel.Arrange(new Rect(new Point(0, 0), ResultsPanel.DesiredSize)); ResultsPanel.UpdateLayout(); String sourceXpsFile = String.Format($"{fileNameWithoutExtension}_test.xps"); File.Delete(sourceXpsFile); using (XpsDocument xpsd = new XpsDocument(sourceXpsFile, FileAccess.Write)) { System.Windows.Xps.XpsDocumentWriter xw = XpsDocument.CreateXpsDocumentWriter(xpsd); xw.Write(fixedDoc); } fixedPage.Children.Remove(ResultsPanel); PdfSharp.Xps.XpsConverter.Convert(sourceXpsFile, fileName, 0); File.Delete(sourceXpsFile); })); } /// /// Injects the data to printed document. Without this the binding data to elements doesn't work. /// /// The document. /// The data source. protected void InjectData(FixedDocument document, object dataSource) { document.DataContext = new { AnalyzerResults = dataSource }; // we need to give the binding infrastructure a push as we // are operating outside of the intended use of WPF var dispatcher = Dispatcher.CurrentDispatcher; dispatcher.Invoke(DispatcherPriority.SystemIdle, new DispatcherOperationCallback(delegate { return null; }), null); } private static Size GetReportSize(ItemsControl reportContainer) { double reportWidth = reportContainer.ActualWidth + 10; double reportHeight = reportContainer.ActualHeight + 10;// (reportWidth / printDialog.PrintableAreaWidth) * printDialog.PrintableAreaHeight; return new Size(reportWidth, reportHeight); } public static void Print(IPlotModel model, string fileName, double width, double height) { using (var stream = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite)) { var exporter = new XpsExporter { Width = width, Height = height}; //PngExporter.Export(this.Plot.ActualModel, fileName, 600, 400, OxyColors.White) exporter.Export(model, stream); } } #endregion #region ExportToExel public async Task ExportResultsToTextFile() { var resultFile = FileHelper.GetResultFilePath(); var dir = Path.GetDirectoryName(resultFile); var name = Path.GetFileNameWithoutExtension(resultFile); string fileNameWithoutExtension = Path.Combine(dir, name); String sourceFile = String.Format($"{fileNameWithoutExtension}s.txt"); File.Delete(sourceFile); await Task.Factory.StartNew(() => { try { List results = AnalyzerResults.ToList(); using (StreamWriter outputFile = new StreamWriter(sourceFile)) { outputFile.WriteLine(String.Format($" {TestName.ToUpper()} RESULTS: ")); outputFile.WriteLine(""); outputFile.WriteLine(""); foreach (var res in results) { if (res.GetType().IsSubclassOf(typeof(AnalyzerResultBase))) { List properties = (res as AnalyzerResultBase).Properties; foreach (var prop in properties) { outputFile.WriteLine(String.Format($" {prop.Name} : {prop.Value}")); } string resV = String.Format($" RESULT = {res.Result.ToString()}"); outputFile.WriteLine(resV); outputFile.WriteLine(""); } } outputFile.Flush(); } } catch (Exception ex) { Debug.WriteLine(ex); } }); } public async void ExportFlowResultsToExcel() { string filePath = (string)Settings.GetValueByName(AnalyzerSettingsEnum.DirectoryPath); if (!Directory.Exists(filePath)) { CommonOpenFileDialog dialog = new CommonOpenFileDialog(); dialog.InitialDirectory = "C:\\Users"; dialog.IsFolderPicker = true; if (dialog.ShowDialog() == CommonFileDialogResult.Ok) { filePath = dialog.FileName; if (filePath.Count(x => x == '%') == 2) { var variable = Regex.Match(filePath, "(?<=%)(.*?)(?=%)").Value; filePath = filePath.Replace($"%{variable}%", Environment.ExpandEnvironmentVariables($"%{variable}%")); } Settings.SetValueByName(AnalyzerSettingsEnum.DirectoryPath, filePath); Settings.SetDefaultPath(filePath); } else { MessageBox.Show("An error occurred while trying to open directory for saving result. ", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); return; } } await Task.Run(() => { ExcelWriter writer = null; ExcelReader reader = null; try { IsFree = false; Stream stream = null; bool dispose = false; if (false == filePath.EndsWith(@"\")) { filePath += @"\"; } String file = filePath + $"DispensersData.xlsx"; if (File.Exists(file)) { //stream = File.OpenRead(file); stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); dispose = true; } else { var b = Assembly.GetExecutingAssembly().GetManifestResourceNames(); stream = EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.DispenserAnalyzer.UI.Templates.DispensersData.xlsx"); } if (stream == null) return; byte[] data = new byte[stream.Length]; stream.Read(data, 0, data.Length); File.WriteAllBytes(file, data); if (dispose) { stream.Dispose(); } reader = new ExcelReader(file); List old_threadCharacteristicsExelModels = reader.GetDataByIndex("Data", 2); reader.Dispose(); reader = null; int maxNumber = old_threadCharacteristicsExelModels.Count > 0 ? old_threadCharacteristicsExelModels.OrderBy(x => x.No___of_test).Max(x => x.No___of_test) : 0; maxNumber++; var time_test = AnalysisService.GetDateTimeString(FileName); var dispenser = AnalysisService.GetDispenserNumber(FileName); int iterations = 0; if (old_threadCharacteristicsExelModels.Count > 0) { var one_existed = old_threadCharacteristicsExelModels.OrderBy(x => x.No___of_test).Count(x => x.DISPENSER == dispenser && x.DATE == time_test); if (one_existed > 0) { InvokeUI(() => { var warningresult = MessageBox.Show($"The result is already saved for the dispenser {dispenser} at time {time_test}. Do you want to save it anyway?", "Warning", MessageBoxButton.YesNo, MessageBoxImage.Question); if(warningresult == MessageBoxResult.Cancel) return; }); } iterations = old_threadCharacteristicsExelModels.OrderBy(x => x.No___of_test).Count(x => x.DISPENSER == dispenser ); } iterations++; //write results List threadCharacteristicsExelModels = new List(); ExcelDataModel model = new ExcelDataModel(); model.No___of_test = maxNumber;//Could be defiend and saved model.DISPENSER = dispenser; model.iteration = iterations; model.Location = FileName.IndexOf("CH8") > 0 ? "Dagesh" : "Twine"; model.DATE = time_test; List results = AnalyzerResults.ToList(); bool firstFlowAverageResult = true; bool firstPrimingResult = true; bool firstErrorResult = true; bool pass = true; foreach (var res in results) { if (res is PrimingAnalyzerResult) { if (firstPrimingResult) { model.PBU___sec__First_cycle = (res as PrimingAnalyzerResult).OnlyTime; firstPrimingResult = false; } else { model.PBU___sec__Second_cycle = (res as PrimingAnalyzerResult).OnlyTime; } } else if (res is FlowAverageAnalyzerResult) { if (firstFlowAverageResult) { model.Average_Value = (res as FlowAverageAnalyzerResult).AverageValue.ToString("0.##"); firstFlowAverageResult = false; if ((res as FlowAverageAnalyzerResult).Result == AnalyzerResultValue.Failed) pass = false; } else { model.AverageValue2 = (res as FlowAverageAnalyzerResult).AverageValue.ToString("0.##"); if ((res as FlowAverageAnalyzerResult).Result == AnalyzerResultValue.Failed) pass = false; } } else if (res is FlowAnalyzerResult) { if (firstErrorResult) { model.Max_Error = (res as FlowAnalyzerResult).PersentageOfError.ToString("0.##"); model.Error__mBr = (res as FlowAnalyzerResult).MaxLocalError.ToString(); model.Trend = (res as FlowAnalyzerResult).Trend; firstErrorResult = false; } else { model.MaxError2 = (res as FlowAnalyzerResult).PersentageOfError.ToString("0.##"); model.Error2 = (res as FlowAnalyzerResult).MaxLocalError.ToString(); model.Trend2 = (res as FlowAnalyzerResult).Trend; } } } model.Test_result = pass ? "Pass" : "Fail"; model.Eng_Recommendations = "-"; model.Last_Action = "-"; threadCharacteristicsExelModels.Add(model); writer = new ExcelWriter(file); writer.WriteData(threadCharacteristicsExelModels, "Data"); writer.Dispose(); writer = null; } catch (Exception ex) { InvokeUI(() => { MessageBox.Show("An error occurred while trying to save results in file DispensersData.xlsx. Error" + ex.Message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); }); } finally { IsFree = true; if (reader != null) reader.Dispose(); if (writer != null) writer.Dispose(); } }); } #endregion #region CompareResults private void Compareresults(object obj) { //List names, List results CompareResultsDlg resultsdlg = new CompareResultsDlg( ResultsToCompare); resultsdlg.Owner = System.Windows.Application.Current.MainWindow; resultsdlg.ShowDialog(); AddToComare = false; ResultsToCompare.ToList().ForEach(x => x.RemoveCompareResultEvent -= OnCompareResultsChanged); ResultsToCompare.Clear(); CompareCommand.RaiseCanExecuteChanged(); } private bool CanCompareresults(object arg) { return ResultsToCompare.Count > 1; } private void OnAddToCompareResults(bool add) { if(add) { if (ResultsToCompare.Count == 3) { ResultsToCompare.RemoveAt(0); } ResultsToCompare.Add( new CompareResultModel(new EventHandler(OnCompareResultsChanged)) { Result= AnalyzerResults[0] as AnalyzerResultBase, IsAddedResult = true, ResultName = Path.GetFileNameWithoutExtension(FileName)}); } if(add == false ) { if (ResultsToCompare.Count > 0) { ResultsToCompare[ResultsToCompare.Count - 1].RemoveCompareResultEvent -= OnCompareResultsChanged; ResultsToCompare.RemoveAt(ResultsToCompare.Count - 1); } } CompareCommand.RaiseCanExecuteChanged(); } public void OnCompareResultsChanged(object sender, EventArgs e) { CompareResultModel result = sender as CompareResultModel; if(result != null && result.IsAddedResult == false) { result.RemoveCompareResultEvent -= OnCompareResultsChanged; ResultsToCompare.Remove(result); CompareCommand.RaiseCanExecuteChanged(); } } public bool CanSaveExel(object arg) { var analyzer = AnalysisService.GetAnalyzer(OpenFilePath); if (analyzer == null) return false; return AnalyzerResults.Count > 0 && analyzer is FlowAnalyser; } private void SaveExel() { if(!IsFree) return; // await ExportRMLToExcel().ConfigureAwait(false); ExportFlowResultsToExcel(); } #endregion } }