/// <summary>
        /// прочитать формулы - описания из строки
        /// </summary>
        public void ReadFromFile()
        {
            criterias = new List <PerformerCriteriaFunction>();

            if (File.Exists(fileName))
            {
                try
                {
                    var doc = new XmlDocument();
                    using (var sr = new StreamReader(fileName, Encoding.UTF8))
                        doc.Load(sr);

                    if (doc.DocumentElement != null)
                    {
                        selectedFunctionIndex = doc.DocumentElement.GetAttributeInt("selected") ?? 0;

                        foreach (XmlElement child in doc.DocumentElement.ChildNodes)
                        {
                            var crit = PerformerCriteriaFunction.ReadFromXml(child);
                            if (crit == null)
                            {
                                continue;
                            }
                            // проверка на дубль и валидность и добавление
                            if (criterias.Any(c => c.AreEqual(crit)))
                            {
                                continue;
                            }

                            string error;
                            if (!ExpressionResolver.CheckFunction(crit.Function, out error, enabledParametersNames))
                            {
                                continue;
                            }
                            criterias.Add(crit);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("Ошибка в PerformerCriteriaFunction - ReadFromFile", ex);
                }
            }

            // добавить обязательные функции
            foreach (var fun in obligatoryFunctions)
            {
                var formula = fun.Function;
                if (criterias.Any(c => c.Function.Equals(formula, StringComparison.OrdinalIgnoreCase)))
                {
                    continue;
                }
                criterias.Add(fun);
            }
        }
        private void BtnCheckFormulaClick(object sender, EventArgs e)
        {
            string error;

            if (!ExpressionResolver.CheckFunction(cbFunction.Text, out error,
                                                  PerformerCriteriaFunctionCollection.Instance.enabledParametersNames))
            {
                MessageBox.Show(error, "Ошибка в формуле", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            // открыть окно проверки формулы подстановкой значений
            new FunctionCheckForm(cbFunction.Text).ShowDialog();
        }
        // "save" button
        private void BtnAcceptClick(object sender, EventArgs e)
        {
            // добавить новый критерий или удалить существующий
            var formula = (cbFunction.Text ?? "").Trim();

            if (lastSelectedItem == null && string.IsNullOrEmpty(formula))
            {
                return;
            }

            // удалить?
            if (string.IsNullOrEmpty(formula))
            {
                if (MessageBox.Show("Удалить формулу \"" + lastSelectedItem.Function + "\"?", "Подтверждение",
                                    MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    return;
                }
                PerformerCriteriaFunctionCollection.Instance.criterias.Remove(lastSelectedItem);
                PerformerCriteriaFunctionCollection.Instance.WriteToFile();
                FillFormulas();
                return;
            }

            // проверить значение
            string error;

            if (!ExpressionResolver.CheckFunction(formula, out error,
                                                  PerformerCriteriaFunctionCollection.Instance.enabledParametersNames))
            {
                MessageBox.Show("Формула \"" + formula + "\" не распознана: " + error);
                return;
            }

            // переписать комментарий
            var existItem = PerformerCriteriaFunctionCollection.Instance.criterias.FirstOrDefault(
                c => c.FormulasEqual(formula));

            if (existItem != null)
            {
                existItem.MarginValue = cbMargin.Checked ? tbMarginValue.Text.ToFloatUniformSafe() : null;
                existItem.Description = tbComment.Text;
                PerformerCriteriaFunctionCollection.Instance.WriteToFile();
                return;
            }

            // добавить новое значение
            var newFunc = new PerformerCriteriaFunction
            {
                Function           = formula,
                Description        = tbComment.Text,
                PreferredSortOrder = cbSortOrder.SelectedIndex == 0 ? SortOrder.Descending : SortOrder.Ascending,
                MarginValue        =
                    cbMargin.Checked ? tbMarginValue.Text.Trim().Replace(",", ".").ToFloatUniformSafe() : null
            };

            PerformerCriteriaFunctionCollection.Instance.criterias.Add(newFunc);
            PerformerCriteriaFunctionCollection.Instance.SelectedFunction = newFunc;
            PerformerCriteriaFunctionCollection.Instance.WriteToFile();
            FillFormulas();
        }