HyperGraph

Добавлены обработчики расчета теорем, сохранения в файл результатов. Добавлена

12/5/2020 4:30:43 PM

Details

diff --git a/HyperGraphModel/Theorem.cs b/HyperGraphModel/Theorem.cs
index b94bf2a..ee5137e 100644
--- a/HyperGraphModel/Theorem.cs
+++ b/HyperGraphModel/Theorem.cs
@@ -25,19 +25,13 @@ namespace HyperGraphModel
         {
             if (Theorem.isEqualNumberOfVertices(Graph))
             {
-                return new TheoremAuto
-                {
-                    isSatisfyTheorem = false,
-                    CountAutomorphism = 0,
-                    AutomorphismNodes = null,
-                    GraphWithoutAutoEdges = null
-                };
+                return default;
             }
 
             //  Копирую гипер-граф, чтобы не изменять исходный
             HyperGraph graph = new HyperGraph(Graph);
             //  Число автоморфизмов
-            Int64 count;
+            long count;
 
             //  Список вершин 0-ого гипер-ребра
             List<string> intersect = new List<string>(graph.HyperEdge[0]);
@@ -79,19 +73,13 @@ namespace HyperGraphModel
         {
             if (!Theorem.isEqualNumberOfVertices(Graph))
             {
-                return new TheoremAuto
-                {
-                    isSatisfyTheorem = false,
-                    CountAutomorphism = 0,
-                    AutomorphismNodes = null,
-                    GraphWithoutAutoEdges = null
-                };
+                return default;
             }
 
             //  Копирую гипер-граф, чтобы не изменять исходный
             HyperGraph graph = new HyperGraph(Graph);
             //  Число автоморфизмов
-            Int64 count = 1;
+            long count = 1;
 
             //  Список вершин 0-ого гипер-ребра
             List<string> intersect = new List<string>(graph.HyperEdge[0]);
@@ -151,7 +139,7 @@ namespace HyperGraphModel
         }
 
 
-        private static Int64 Factorial(int input)
+        private static long Factorial(int input)
         {
             //  Предрассчитанные значения
             switch (input)
@@ -167,7 +155,7 @@ namespace HyperGraphModel
                     break;
             }
             int x;
-            Int64 fact = 1;
+            long fact = 1;
             try
             {
                 //  Вдруг выйдем за пределы максимального значения
@@ -183,11 +171,11 @@ namespace HyperGraphModel
             return fact;
         }
 
-        private static Int64 Pow(Int64 input, Int64 grade)
+        private static long Pow(long input, long grade)
         {
             if (grade < 0)
                 throw new Exception("error");
-            Int64 result = 1;
+            long result = 1;
             for (int i = 0; i < grade; i++)
                 result *= input;
             return result;
diff --git a/WPF/Common/Assets/Icon.ico b/WPF/Common/Assets/Icon.ico
new file mode 100644
index 0000000..7ed5cb2
Binary files /dev/null and b/WPF/Common/Assets/Icon.ico differ
diff --git a/WPF/Common/Helpers/IniFile.cs b/WPF/Common/Helpers/IniFile.cs
index e376ada..aad574f 100644
--- a/WPF/Common/Helpers/IniFile.cs
+++ b/WPF/Common/Helpers/IniFile.cs
@@ -53,7 +53,7 @@ namespace Common.Helpers
             {
                 var value = Read(key, section).Split(new[] {"###"}, StringSplitOptions.None);
                 if (value.Length >= position && 
-                    (!isNumber || (Double.TryParse(value[position], NumberStyles.Any, CultureInfo.InvariantCulture, out doubVal) || (int.TryParse(value[position], out intVal)))))
+                    (!isNumber || (double.TryParse(value[position], NumberStyles.Any, CultureInfo.InvariantCulture, out doubVal) || (int.TryParse(value[position], out intVal)))))
                     rezult.Add(key, value[position]);
             }
             return rezult;
diff --git a/WPF/Common/Helpers/StatusBar.cs b/WPF/Common/Helpers/StatusBar.cs
index fcb1160..af1c81f 100644
--- a/WPF/Common/Helpers/StatusBar.cs
+++ b/WPF/Common/Helpers/StatusBar.cs
@@ -25,7 +25,7 @@ namespace Common.Helpers
         {
            IsVisible = false;
            Status = Status.Default;
-           Message = String.Empty;
+           Message = string.Empty;
         }
 
         private Status _status;
diff --git a/WPF/Common/Parameters/Parameter.cs b/WPF/Common/Parameters/Parameter.cs
index f7f7317..ea341ec 100644
--- a/WPF/Common/Parameters/Parameter.cs
+++ b/WPF/Common/Parameters/Parameter.cs
@@ -15,7 +15,7 @@ namespace Common.Parameters
         protected Parameter()
         {
             Status = Status.Normal;
-            ErrorShortDescr = String.Empty;
+            ErrorShortDescr = string.Empty;
             IsVisible = true;
             IsEnabled = true;
         }
@@ -45,7 +45,7 @@ namespace Common.Parameters
         public string ErrorShortDescr { get; set; }
         public void ResetValidation()
         {
-            ErrorShortDescr = String.Empty;
+            ErrorShortDescr = string.Empty;
             ErrorCount = 0;
             ErrorWarningCount = 0;
             ErrorMessage = null;
diff --git a/WPF/Common/WPF/Controls/TreeGridViewRowPresenter.cs b/WPF/Common/WPF/Controls/TreeGridViewRowPresenter.cs
index d83c29e..b65d307 100644
--- a/WPF/Common/WPF/Controls/TreeGridViewRowPresenter.cs
+++ b/WPF/Common/WPF/Controls/TreeGridViewRowPresenter.cs
@@ -11,7 +11,7 @@ namespace Common.WPF.Controls
 {
 	public class TreeGridViewRowPresenter : GridViewRowPresenter
 	{
-		public static DependencyProperty FirstColumnIndentProperty = DependencyProperty.Register("FirstColumnIndent", typeof(Double), typeof(TreeGridViewRowPresenter), new PropertyMetadata(0d));
+		public static DependencyProperty FirstColumnIndentProperty = DependencyProperty.Register("FirstColumnIndent", typeof(double), typeof(TreeGridViewRowPresenter), new PropertyMetadata(0d));
 		public static DependencyProperty ExpanderProperty = DependencyProperty.Register("Expander", typeof(UIElement), typeof(TreeGridViewRowPresenter), new FrameworkPropertyMetadata(null, OnExpanderChanged));
 
 		UIElementCollection _childs;
@@ -26,9 +26,9 @@ namespace Common.WPF.Controls
 			dpd?.AddValueChanged(this, (s, e) => EnsureLines());
 		}
 
-		public Double FirstColumnIndent
+		public double FirstColumnIndent
 		{
-			get { return (Double)GetValue(FirstColumnIndentProperty); }
+			get { return (double)GetValue(FirstColumnIndentProperty); }
 			set { SetValue(FirstColumnIndentProperty, value); }
 		}
 
@@ -106,7 +106,7 @@ namespace Common.WPF.Controls
 				UIElement uiColumn = (UIElement)base.GetVisualChild((int)_actualIndexProperty.GetValue(column, null));
 
 				// Compute column width
-				double w = Math.Min(max, Double.IsNaN(column.Width) ? (double)_desiredWidthProperty.GetValue(column, null) : column.Width);
+				double w = Math.Min(max, double.IsNaN(column.Width) ? (double)_desiredWidthProperty.GetValue(column, null) : column.Width);
 
 				// First column indent
 				Rect rect;
diff --git a/WPF/Common/WPF/Converters/LevelToIndentConverter.cs b/WPF/Common/WPF/Converters/LevelToIndentConverter.cs
index b2c08e5..d7297ea 100644
--- a/WPF/Common/WPF/Converters/LevelToIndentConverter.cs
+++ b/WPF/Common/WPF/Converters/LevelToIndentConverter.cs
@@ -12,9 +12,9 @@ namespace Common.WPF.Converters
 	{
 		public object Convert(object o, Type type, object parameter, CultureInfo culture)
 		{
-			Double indentSize = 5;
+            double indentSize = 5;
 			if (parameter != null)
-				Double.TryParse(parameter.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out indentSize);
+                double.TryParse(parameter.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out indentSize);
 
 			return (int)o * indentSize + " 0 0 0";
 		}
diff --git a/WPF/Common/WPF/Dictionary.xaml b/WPF/Common/WPF/Dictionary.xaml
index 9eba151..9ead7c0 100644
--- a/WPF/Common/WPF/Dictionary.xaml
+++ b/WPF/Common/WPF/Dictionary.xaml
@@ -7,10 +7,11 @@
     <converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
     <converters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter"/>
     <converters:InversedBoolToVisibilityConverter x:Key="InversedBoolToVisibilityConverter"/>
+    <converters:StatusToColorConverter x:Key="StatusToColorConverter"/>
 
     <Style TargetType="{x:Type Button}" BasedOn="{StaticResource DefaultButton}"/>
 
-    <!--<BitmapImage x:Key="MainIcon" UriSource="pack://application:,,,/PasswordApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null;component/storage.ico"  />-->
+    <BitmapImage x:Key="MainIcon" UriSource="pack://application:,,,/WPF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null;component/Common/Assets/Icon.ico"  />
 
     <ResourceDictionary.MergedDictionaries>
         <ResourceDictionary Source="Style/TextBlockStyle.xaml" />

WPF/Icon.ico 0(+0 -0)

diff --git a/WPF/Icon.ico b/WPF/Icon.ico
new file mode 100644
index 0000000..7ed5cb2
Binary files /dev/null and b/WPF/Icon.ico differ

WPF/Model/Calculate.cs 187(+96 -91)

diff --git a/WPF/Model/Calculate.cs b/WPF/Model/Calculate.cs
index dc9ae1b..a6bc93c 100644
--- a/WPF/Model/Calculate.cs
+++ b/WPF/Model/Calculate.cs
@@ -1,8 +1,8 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using WPF.ViewModel;
+using System.IO;
 
 using HyperGraphModel;
 using TheoremAuto = HyperGraphModel.Theorem.TheoremAuto;
@@ -15,25 +15,33 @@ namespace WPF.Model
 
         public static void CreateGraph(int Edges, int SameVert, List<int> Verticies)
         {
-            var vert = Verticies.Sum(x => x - SameVert) + SameVert;
-            var matrix = new Matrix<int>(vert, Edges);
-
-            //  заполнение ребер отдельными вершинами
-            for (int j = 0, i = 0; j < Verticies.Count; j++)
+            try
             {
-                int k = 0;
-                while (Verticies[j] - SameVert > k)
+                var vert = Verticies.Sum(x => x - SameVert) + SameVert;
+                var matrix = new Matrix<int>(vert, Edges);
+
+                //  заполнение ребер отдельными вершинами
+                for (int j = 0, i = 0; j < Verticies.Count; j++)
                 {
-                    matrix[i++, j] = 1;
-                    k++;
+                    int k = 0;
+                    while (Verticies[j] - SameVert > k)
+                    {
+                        matrix[i++, j] = 1;
+                        k++;
+                    }
                 }
-            }
-            //  заполнение ребер общими вершинами
-            for (int i = vert - SameVert; i < vert; i++)
-                for (int j = 0; j < matrix.countColumn; j++)
-                    matrix[i, j] = 1;
+                //  заполнение ребер общими вершинами
+                for (int i = vert - SameVert; i < vert; i++)
+                    for (int j = 0; j < matrix.countColumn; j++)
+                        matrix[i, j] = 1;
 
-            Graph = new HyperGraph(matrix);
+                Graph = new HyperGraph(matrix);
+            }
+            catch (Exception e)
+            {
+                MainViewModel.Current.Status = Common.Status.Error;
+                MainViewModel.Current.StatusMessage = e.Message;
+            }
         }
 
         public static TheoremAuto TheoremSecond()
@@ -43,20 +51,13 @@ namespace WPF.Model
                 if (Graph == null)
                     throw new Exception("Гипер граф не существует");
 
-                var result = Theorem.TheoremAutomorphism(Graph);
-                ExampleTheorema(Graph, output);
-
-                return result;
+                return Theorem.TheoremAutomorphism(Graph);
             }
             catch (Exception e)
             {
-                return new TheoremAuto
-                {
-                    AutomorphismNodes = null,
-                    isSatisfyTheorem = false,
-                    CountAutomorphism = 0,
-                    GraphWithoutAutoEdges = null
-                };
+                MainViewModel.Current.Status = Common.Status.Error;
+                MainViewModel.Current.StatusMessage = e.Message;
+                return default;
             }
         }
 
@@ -67,76 +68,50 @@ namespace WPF.Model
                 if (Graph == null)
                     throw new Exception("Гипер граф не существует");
 
-                var result = Theorem.TheoremAutomorphismForEqualNumberOfVertices(Graph);
-                ExampleTheoremaThird(Graph, output);
-
-                return result;
+                return Theorem.TheoremAutomorphismForEqualNumberOfVertices(Graph);
             }
             catch (Exception e)
             {
-                return new TheoremAuto
-                {
-                    AutomorphismNodes = null,
-                    isSatisfyTheorem = false,
-                    CountAutomorphism = 0,
-                    GraphWithoutAutoEdges = null
-                };
+                MainViewModel.Current.Status = Common.Status.Error;
+                MainViewModel.Current.StatusMessage = e.Message;
+                return default;
             }
         }
 
-        #region Private методы
-
-        //  Все перестановки графа вывести в файл
-        static void ExampleAllTranspos(HyperGraph graph, System.IO.StreamWriter output)
+        public static MemoryStream Export(TheoremAuto result, EnumTheorem theorem)
         {
-            //  Массив (лист) всех возможных перестановок одного множества (гипер-ребра)
-            List<List<string>> transpos;
-
-            //  Обработать все гипер-ребра
-            for (int i = 0; i < graph.HyperEdge.Count; i++)
+            MemoryStream memoryStream = new MemoryStream();
+            switch (theorem)
             {
-                //  Получить массив перестановок текущего гипер-ребра
-                transpos = Combinatorics<string>.Transposition(graph.HyperEdge[i]);
-
-                // Вывод всех вершин текущего гипер-ребра 
-                output.Write("Текущее ребро включает вершины:");
-                for (int g = 0; g < graph.HyperEdge[i].Count; g++)
-                {
-                    output.Write(" {0}", graph.HyperEdge[i][g]);
-                }
-
-                //  Вывод всех перестановок текущего гипер-ребра
-                output.WriteLine();
-
-                //  Вывод начальной перестановки
-                output.Write("1:");
-                for (int g = 0; g < graph.HyperEdge[i].Count; g++)
-                {
-                    output.Write(" {0}", graph.HyperEdge[i][g]);
-                }
-
-                output.WriteLine("\r\n\t-----------");
-                //  Алгоритм перестановок не учитывает начальную, а начинает со следующей
-                for (int g = 0; g < transpos.Count; g++)
-                {
-                    output.Write("{0}: ", g + 2);
-                    for (int f = 0; f < transpos[g].Count; f++)
+                case EnumTheorem.Second:
                     {
-                        output.Write("{0} ", transpos[g][f]);
+                        using (StreamWriter sw = new StreamWriter(memoryStream))
+                        {
+                            ExportTheoremaSecond(result, sw);
+                        }
+                        break;
                     }
+                case EnumTheorem.Third:
+                    {
+                        using (StreamWriter sw = new StreamWriter(memoryStream))
+                        {
+                            ExportTheoremaThird(result, sw);
+                        }
+                        break;
+                    }
+                case EnumTheorem.Forth:
+                    {
 
-                    output.WriteLine("\r\n\t-----------");
-                }
-                output.WriteLine();
+                        break;
+                    }
             }
+            return memoryStream;
         }
 
-        //  Найти общие вершины для всех гипер-ребер, подсчитать количество автоморфизмов гипер-графа и вывести все перестановки оставшихся ребер
-        static void ExampleTheorema(HyperGraph graph, System.IO.StreamWriter output)
-        {
-            //  Получить результат вычислений
-            var result = Theorem.TheoremAutomorphism(graph);
+        #region Private методы
 
+        static void ExportTheoremaSecond(TheoremAuto result, StreamWriter output)
+        {
             //  Выполняется ли условие согласно теореме 2
             output.WriteLine("Согласно теореме 2: " + result.isSatisfyTheorem);
             //  Если да, то вывести
@@ -174,18 +149,48 @@ namespace WPF.Model
 
                 output.WriteLine("\r\nКоличество автоморфизмов: " + result.CountAutomorphism + "\r\n");
 
-                //  Вывести перестановки в файл
-                ExampleAllTranspos(result.GraphWithoutAutoEdges, output);
+                //  Обработать все гипер-ребра
+                for (int i = 0; i < result.GraphWithoutAutoEdges.HyperEdge.Count; i++)
+                {
+                    //  Получить массив перестановок текущего гипер-ребра
+                    transpos = Combinatorics<string>.Transposition(result.GraphWithoutAutoEdges.HyperEdge[i]);
+
+                    // Вывод всех вершин текущего гипер-ребра 
+                    output.Write("Текущее ребро включает вершины:");
+                    for (int g = 0; g < result.GraphWithoutAutoEdges.HyperEdge[i].Count; g++)
+                    {
+                        output.Write(" {0}", result.GraphWithoutAutoEdges.HyperEdge[i][g]);
+                    }
+
+                    //  Вывод всех перестановок текущего гипер-ребра
+                    output.WriteLine();
+
+                    //  Вывод начальной перестановки
+                    output.Write("1:");
+                    for (int g = 0; g < result.GraphWithoutAutoEdges.HyperEdge[i].Count; g++)
+                    {
+                        output.Write(" {0}", result.GraphWithoutAutoEdges.HyperEdge[i][g]);
+                    }
+
+                    output.WriteLine("\r\n\t-----------");
+                    //  Алгоритм перестановок не учитывает начальную, а начинает со следующей
+                    for (int g = 0; g < transpos.Count; g++)
+                    {
+                        output.Write("{0}: ", g + 2);
+                        for (int f = 0; f < transpos[g].Count; f++)
+                        {
+                            output.Write("{0} ", transpos[g][f]);
+                        }
+
+                        output.WriteLine("\r\n\t-----------");
+                    }
+                    output.WriteLine();
+                }
             }
-            //  Уничтожить временный граф
-            result.GraphWithoutAutoEdges.Dispose();
         }
 
-        static void ExampleTheoremaThird(HyperGraph Graph, System.IO.StreamWriter output)
+        static void ExportTheoremaThird(TheoremAuto result, StreamWriter output)
         {
-            //  Подсчет количества и получение гипер-графа без общих вершин
-            var result = Theorem.TheoremAutomorphismForEqualNumberOfVertices(Graph);
-
             //  Выполняется ли условие согласно теореме 3
             output.WriteLine("Согласно теореме 3: " + result.isSatisfyTheorem);
             //  Если да, то вывести
diff --git a/WPF/Model/ObservableCollectionExtension.cs b/WPF/Model/ObservableCollectionExtension.cs
new file mode 100644
index 0000000..1a9b085
--- /dev/null
+++ b/WPF/Model/ObservableCollectionExtension.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+
+namespace WPF.Model
+{
+
+    public static class ObservableCollectionExtension
+    {
+        public static void NotifyPropertyChanged<T>(this ObservableCollection<T> observableCollection, Action<T, PropertyChangedEventArgs> callBackAction)
+            where T : INotifyPropertyChanged
+        {
+            observableCollection.CollectionChanged += (sender, args) =>
+            {
+                //Does not prevent garbage collection says: http://stackoverflow.com/questions/298261/do-event-handlers-stop-garbage-collection-from-occuring
+                //publisher.SomeEvent += target.SomeHandler;
+                //then "publisher" will keep "target" alive, but "target" will not keep "publisher" alive.
+
+                //if (args.NewItems == null)
+                //    return;
+                //foreach (T item in args.NewItems)
+                //{
+                //    item.PropertyChanged += (obj, eventArgs) =>
+                //    {
+                //        callBackAction((T)obj, eventArgs);
+                //    };
+                //}
+
+                if (args.OldItems != null)
+                    foreach (T item in args.OldItems)
+                        if (item != null && item is INotifyPropertyChanged i)
+                            i.PropertyChanged -= (obj, eventArgs) =>
+                            {
+                                callBackAction((T)obj, eventArgs);
+                            };
+
+
+                if (args.NewItems != null)
+                    foreach (T item in args.NewItems)
+                        if (item != null && item is INotifyPropertyChanged i)
+                        {
+                            i.PropertyChanged -= (obj, eventArgs) =>
+                            {
+                                callBackAction((T)obj, eventArgs);
+                            };
+
+                            i.PropertyChanged += (obj, eventArgs) =>
+                            {
+                                callBackAction((T)obj, eventArgs);
+                            };
+                        };
+
+            };
+        }
+    }
+}
diff --git a/WPF/View/MainWindow.xaml b/WPF/View/MainWindow.xaml
index e251923..3998e73 100644
--- a/WPF/View/MainWindow.xaml
+++ b/WPF/View/MainWindow.xaml
@@ -13,13 +13,14 @@
         x:Name="Window"
         WindowState="{Binding WindowState}"
         Background="{StaticResource WindowBackground}"
+        Icon="{StaticResource MainIcon}"
         WindowStyle="None"
         ResizeMode="CanResizeWithGrip"
         AllowsTransparency="True"
         Loaded="Window_Loaded"
         Title="{Binding TitleText}" 
-        Height="215" Width="725"
-        MinHeight="215" MinWidth="725"
+        Height="235" Width="725"
+        MinHeight="235" MinWidth="725"
         BorderBrush="#FF494957"
         BorderThickness="1">
     <Window.Resources>
@@ -51,8 +52,9 @@
     </Window.Resources>
     <Grid>
         <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto"/>
             <RowDefinition Height="*" />
+            <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
 
         <Grid Grid.Row="0" Background="{StaticResource WindowBackground}" x:Name="Header">
@@ -218,10 +220,24 @@
                 <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding AutomorphismCount}" Margin="5 0" VerticalAlignment="Bottom" TextAlignment="Center" FontWeight="Bold" FontSize="18" Foreground="{StaticResource Yellow}" MinWidth="100"/>
 
             </Grid>
-            
-            
+
+
 
         </Grid>
 
+        <StackPanel Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{Binding Status, Converter={StaticResource StatusToColorConverter}}" Margin="0,1,0,0">
+            <TextBlock Text="{Binding StatusMessage}" FontSize="16" VerticalAlignment="Center" Margin="5 3 0 0" />
+
+            <!--<StackPanel.Style>
+                <Style TargetType="StackPanel">
+                    <Setter Property="Visibility" Value="Visible"/>
+                    <Style.Triggers>
+                        <DataTrigger Binding="{Binding Status}" Value="{x:Static status:Status.Normal}">
+                            <Setter Property="Visibility" Value="Collapsed"/>
+                        </DataTrigger>
+                    </Style.Triggers>
+                </Style>
+            </StackPanel.Style>-->
+        </StackPanel>
     </Grid>
 </Window>
diff --git a/WPF/ViewModel/MainViewModel.cs b/WPF/ViewModel/MainViewModel.cs
index e833ced..1a7b864 100644
--- a/WPF/ViewModel/MainViewModel.cs
+++ b/WPF/ViewModel/MainViewModel.cs
@@ -1,4 +1,5 @@
 using Common.WPF;
+using Common;
 //using WPF.Helpers;
 using WPF.Model;
 using System;
@@ -6,7 +7,8 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.IO;
 using System.Linq;
-using System.Threading.Tasks;
+using System.ComponentModel;
+using System.Windows.Forms;
 using Visibility = System.Windows.Visibility;
 using TheoremAuto = HyperGraphModel.Theorem.TheoremAuto;
 using static WPF.Model.Calculate;
@@ -17,26 +19,43 @@ namespace WPF.ViewModel
     {
         public MainViewModel() : base()
         {
+            Current = this;
+
             Verticies = new ObservableCollection<VertViewModel>();
+            Verticies.NotifyPropertyChanged((obj, notifyPropertyChangedEventArgs) =>
+            {
+                SetResultDefault();
+            });
+
             EnumTheorems = Enum.GetValues(typeof(EnumTheorem)).Cast<EnumTheorem>().ToList();
             SelectedTheorem = EnumTheorems.First();
             EdgesNum = 1;
             SameVertNum = 1;
-            IsTheoremCorrect = false;
-            AutomorphismCount = 0;
+            PathToSave = DefaultPathToSave;
 
             CalculateCommand = new RelayCommand(OnCalculate);
-            SaveResultCommand = new RelayCommand(OnSaveResult);
+            SaveResultCommand = new RelayCommand(OnSaveResult, () => IsTheoremCorrect);
 
             //AddItemCommand = new RelayCommand<ItemViewModel>(OnAddItem, item => Items.FirstOrDefault(e => e.Value == item.Value) == null);
             //RemoveItemCommand = new RelayCommand<ItemViewModel>(OnRemoveItem, item => !item.Readonly);
 
             //SwitchDataVisibleCommand = new RelayCommand(OnSwitchDataVisible);
             //ClearSearchCommand = new RelayCommand(OnClearSearch);
+
+            EdgesNum = 3;
+            SameVertNum = 1;
+            Verticies[0].Value = 4;
+            Verticies[1].Value = 4;
+            Verticies[2].Value = 4;
         }
 
         #region Поля и свойства
 
+        public static MainViewModel Current { get; private set; }
+
+        private readonly string DefaultPathToSave = $"C:\\Users\\{Environment.UserName}\\Documents\\";
+        private string PathToSave { get; set; }
+
         public static int MaxValue { get; } = 99;
         public static int MinValue { get; } = 0;
 
@@ -48,6 +67,7 @@ namespace WPF.ViewModel
             set
             {
                 _selectedTheorem = value;
+                SetResultDefault();
                 OnPropertyChanged(() => SelectedTheorem);
             }
 
@@ -61,6 +81,7 @@ namespace WPF.ViewModel
             set
             {
                 _edgesNum = value;
+                SetResultDefault();
                 OnPropertyChanged(() => EdgesNum);
                 UpdateVerticies();
                 OnPropertyChanged(() => VisibilityVerticies);
@@ -74,6 +95,7 @@ namespace WPF.ViewModel
             set
             {
                 _sameVertNum = value;
+                SetResultDefault();
                 OnPropertyChanged(() => SameVertNum);
                 UpdateVerticiesValue();
                 OnPropertyChanged(() => VisibilityVerticies);
@@ -132,6 +154,41 @@ namespace WPF.ViewModel
             }
         }
 
+        private TheoremAuto _result;
+        public TheoremAuto Result
+        {
+            get => _result;
+            set
+            {
+                _result = value;
+                IsTheoremCorrect = value.isSatisfyTheorem;
+                AutomorphismCount = value.CountAutomorphism;
+                OnPropertyChanged(() => Result);
+            }
+        }
+
+        private Status _status;
+        public Status Status
+        {
+            get { return _status; }
+            set
+            {
+                _status = value;
+                OnPropertyChanged(() => Status);
+            }
+        }
+
+        private string _statusMessage;
+        public string StatusMessage
+        {
+            get { return _statusMessage; }
+            set
+            {
+                _statusMessage = value;
+                OnPropertyChanged(() => StatusMessage);
+            }
+        }
+
         #endregion
 
         #region Методы и команды
@@ -151,15 +208,10 @@ namespace WPF.ViewModel
             }
             else if (EdgesNum < Verticies.Count)
             {
-                if (EdgesNum == 0)
-                    Verticies.Clear();
-                else
+                var skip = Verticies.Skip(EdgesNum).ToList();
+                foreach (var vert in skip)
                 {
-                    var skip = Verticies.Skip(EdgesNum).ToList();
-                    foreach (var vert in skip)
-                    {
-                        Verticies.Remove(vert);
-                    }
+                    Verticies.Remove(vert);
                 }
             }
         }
@@ -174,38 +226,76 @@ namespace WPF.ViewModel
             }
         }
 
-
         public RelayCommand CalculateCommand { get; }
         private void OnCalculate()
         {
             CreateGraph(EdgesNum, SameVertNum, Verticies.Select(x => x.Value).ToList());
-            TheoremAuto result = default;
+            SetResultDefault();
             switch (SelectedTheorem)
             {
                 case EnumTheorem.Second:
                     {
-                        result = TheoremSecond();
+                        Result = TheoremSecond();
+                        Status = Status.OperationSuccess;
+                        StatusMessage = "Расчет успешно выполнен";
                         break;
                     }
                 case EnumTheorem.Third:
                     {
-                        result = TheoremThird();
+                        Result = TheoremThird();
+                        Status = Status.OperationSuccess;
+                        StatusMessage = "Расчет успешно выполнен";
                         break;
                     }
                 case EnumTheorem.Forth:
                     {
 
+                        Status = Status.OperationSuccess;
+                        StatusMessage = "Расчет успешно выполнен";
                         break;
                     }
             }
-            IsTheoremCorrect = result.isSatisfyTheorem;
-            AutomorphismCount = result.CountAutomorphism;
         }
 
         public RelayCommand SaveResultCommand { get; }
         private void OnSaveResult()
         {
+            if (!Directory.Exists(PathToSave))
+                PathToSave = DefaultPathToSave;
+
+            var streamResult = Export(Result, SelectedTheorem);
+
+            if (streamResult.CanRead && streamResult.Length == 0)
+            {
+                Status = Status.Error;
+                StatusMessage = "Ошибка экспорта. Поток экспорта пустой.";
+                streamResult.Close();
+                return;
+            }
 
+            using (SaveFileDialog saveFileDialog = new SaveFileDialog()
+            {
+                Filter = "Text file (*.txt)|*.txt",/*"Text file (*.txt)|*.txt|C# file (*.cs)|*.cs",*/
+                InitialDirectory = PathToSave
+            })
+            {
+                if (saveFileDialog.ShowDialog() == DialogResult.OK)
+                {
+                    PathToSave = Path.GetDirectoryName(saveFileDialog.FileName);
+                    File.WriteAllBytes(saveFileDialog.FileName, streamResult.ToArray());
+
+                    Status = Status.OperationSuccess;
+                    StatusMessage = $"Файл успешно сохранен: {saveFileDialog.FileName}";
+                }
+            }
+
+        }
+
+        private void SetResultDefault()
+        {
+            Result = default;
+            Status = Status.Default;
+            StatusMessage = "Результат успешно сброшен";
         }
 
         #endregion

WPF/WPF.csproj 11(+8 -3)

diff --git a/WPF/WPF.csproj b/WPF/WPF.csproj
index ac80020..16e9ca4 100644
--- a/WPF/WPF.csproj
+++ b/WPF/WPF.csproj
@@ -36,6 +36,10 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationIcon>
+    </ApplicationIcon>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="Costura, Version=4.1.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
       <HintPath>..\packages\Costura.Fody.4.1.0\lib\net40\Costura.dll</HintPath>
@@ -280,6 +284,7 @@
     <Compile Include="Common\WPF\ObservableCollectionAdv.cs" />
     <Compile Include="Common\WPF\RelayCommand.cs" />
     <Compile Include="Model\Calculate.cs" />
+    <Compile Include="Model\ObservableCollectionExtension.cs" />
     <Compile Include="Model\EnumTheorem.cs" />
     <Compile Include="ViewModel\MainViewModel.cs" />
     <Compile Include="View\MainWindow.xaml.cs">
@@ -320,13 +325,13 @@
       <Name>HyperGraphModel</Name>
     </ProjectReference>
   </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Common\Assets\" />
-  </ItemGroup>
+  <ItemGroup />
   <ItemGroup>
     <Resource Include="FodyWeavers.xml" />
   </ItemGroup>
   <ItemGroup>
+    <Resource Include="Icon.ico" />
+    <Resource Include="Common\Assets\Icon.ico" />
     <Content Include="Common\Microsoft.Windows.Shell.dll" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />