2
\$\begingroup\$

This code is part of a VSTO add-in for Excel. As the title states it solves systems of linear equations by allowing the user to select the appropriate ranges. The code works and covers most issues I could think of. The form is displayed by a button click from the ribbon. The selection of ranges is accomplished by clicking respective buttons on the form and selecting Range objects on a sheet via the InputBox where Type: 8 stands for a Range object.

The problem is everything is coded in the code behind for the from, something that doesn't allow for code reuse. What can be done to foster code reuse? I've read about the Model-View-Presenter and think this pattern is applicable. I'm presently unable to bridge the gap between reading about it and writing code according to that pattern. If MVP isn't applicable then what pattern would best suited?

Code generated by the designer.

//SystemsOfEquationsView.Designer.cs  is of the type `System.Windows.Forms.Form`.
namespace ExcelAddIn1.System_Of_Linear_Equations
{
    partial class SystemsOfEquationsView
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.SelectAnswerVectorBotton = new System.Windows.Forms.Button();
            this.SelectCoefficientButton = new System.Windows.Forms.Button();
            this.AnswerVectorDisplay = new System.Windows.Forms.TextBox();
            this.CoefficientMatrixDisplay = new System.Windows.Forms.TextBox();
            this.AnswerVectorLabel = new System.Windows.Forms.Label();
            this.CoefficientMatrixLabel = new System.Windows.Forms.Label();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.SelectSolutionButton = new System.Windows.Forms.Button();
            this.SelectInverseCoefficientButton = new System.Windows.Forms.Button();
            this.SolutionVectorDisplay = new System.Windows.Forms.TextBox();
            this.InverseCoefficientMatrixDisplay = new System.Windows.Forms.TextBox();
            this.SolutionVectorLabel = new System.Windows.Forms.Label();
            this.InverseCoefficientMatrixLabel = new System.Windows.Forms.Label();
            this.ClearButton = new System.Windows.Forms.Button();
            this.SolveButton = new System.Windows.Forms.Button();
            this.groupBox1.SuspendLayout();
            this.groupBox2.SuspendLayout();
            this.SuspendLayout();
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.SelectAnswerVectorBotton);
            this.groupBox1.Controls.Add(this.SelectCoefficientButton);
            this.groupBox1.Controls.Add(this.AnswerVectorDisplay);
            this.groupBox1.Controls.Add(this.CoefficientMatrixDisplay);
            this.groupBox1.Controls.Add(this.AnswerVectorLabel);
            this.groupBox1.Controls.Add(this.CoefficientMatrixLabel);
            this.groupBox1.Location = new System.Drawing.Point(12, 12);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(474, 86);
            this.groupBox1.TabIndex = 0;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Inputs";
            // 
            // SelectAnswerVectorBotton
            // 
            this.SelectAnswerVectorBotton.Location = new System.Drawing.Point(335, 57);
            this.SelectAnswerVectorBotton.Name = "SelectAnswerVectorBotton";
            this.SelectAnswerVectorBotton.Size = new System.Drawing.Size(128, 23);
            this.SelectAnswerVectorBotton.TabIndex = 5;
            this.SelectAnswerVectorBotton.Text = "Select Answer Vector";
            this.SelectAnswerVectorBotton.UseVisualStyleBackColor = true;
            this.SelectAnswerVectorBotton.Click += new System.EventHandler(this.SelectAnswerVectorBotton_Click);
            // 
            // SelectCoefficientButton
            // 
            this.SelectCoefficientButton.Location = new System.Drawing.Point(156, 57);
            this.SelectCoefficientButton.Name = "SelectCoefficientButton";
            this.SelectCoefficientButton.Size = new System.Drawing.Size(100, 23);
            this.SelectCoefficientButton.TabIndex = 4;
            this.SelectCoefficientButton.Text = "Select Coefficient";
            this.SelectCoefficientButton.UseVisualStyleBackColor = true;
            this.SelectCoefficientButton.Click += new System.EventHandler(this.SelectCoefficientButton_Click);
            // 
            // AnswerVectorDisplay
            // 
            this.AnswerVectorDisplay.Enabled = false;
            this.AnswerVectorDisplay.Location = new System.Drawing.Point(349, 31);
            this.AnswerVectorDisplay.Name = "AnswerVectorDisplay";
            this.AnswerVectorDisplay.ReadOnly = true;
            this.AnswerVectorDisplay.Size = new System.Drawing.Size(100, 20);
            this.AnswerVectorDisplay.TabIndex = 3;
            // 
            // CoefficientMatrixDisplay
            // 
            this.CoefficientMatrixDisplay.Enabled = false;
            this.CoefficientMatrixDisplay.Location = new System.Drawing.Point(156, 31);
            this.CoefficientMatrixDisplay.Name = "CoefficientMatrixDisplay";
            this.CoefficientMatrixDisplay.ReadOnly = true;
            this.CoefficientMatrixDisplay.Size = new System.Drawing.Size(100, 20);
            this.CoefficientMatrixDisplay.TabIndex = 2;
            // 
            // AnswerVectorLabel
            // 
            this.AnswerVectorLabel.AutoSize = true;
            this.AnswerVectorLabel.Location = new System.Drawing.Point(268, 34);
            this.AnswerVectorLabel.Name = "AnswerVectorLabel";
            this.AnswerVectorLabel.Size = new System.Drawing.Size(75, 13);
            this.AnswerVectorLabel.TabIndex = 1;
            this.AnswerVectorLabel.Text = "Answer vector";
            // 
            // CoefficientMatrixLabel
            // 
            this.CoefficientMatrixLabel.AutoSize = true;
            this.CoefficientMatrixLabel.Location = new System.Drawing.Point(63, 34);
            this.CoefficientMatrixLabel.Name = "CoefficientMatrixLabel";
            this.CoefficientMatrixLabel.Size = new System.Drawing.Size(87, 13);
            this.CoefficientMatrixLabel.TabIndex = 0;
            this.CoefficientMatrixLabel.Text = "Coefficient matrix";
            // 
            // groupBox2
            // 
            this.groupBox2.Controls.Add(this.SelectSolutionButton);
            this.groupBox2.Controls.Add(this.SelectInverseCoefficientButton);
            this.groupBox2.Controls.Add(this.SolutionVectorDisplay);
            this.groupBox2.Controls.Add(this.InverseCoefficientMatrixDisplay);
            this.groupBox2.Controls.Add(this.SolutionVectorLabel);
            this.groupBox2.Controls.Add(this.InverseCoefficientMatrixLabel);
            this.groupBox2.Location = new System.Drawing.Point(12, 104);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(474, 86);
            this.groupBox2.TabIndex = 1;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "Outputs: Top left cell";
            // 
            // SelectSolutionButton
            // 
            this.SelectSolutionButton.Location = new System.Drawing.Point(335, 57);
            this.SelectSolutionButton.Name = "SelectSolutionButton";
            this.SelectSolutionButton.Size = new System.Drawing.Size(128, 23);
            this.SelectSolutionButton.TabIndex = 6;
            this.SelectSolutionButton.Text = "Select Solution Vector";
            this.SelectSolutionButton.UseVisualStyleBackColor = true;
            this.SelectSolutionButton.Click += new System.EventHandler(this.SelectSolutionButton_Click);
            // 
            // SelectInverseCoefficientButton
            // 
            this.SelectInverseCoefficientButton.Location = new System.Drawing.Point(156, 57);
            this.SelectInverseCoefficientButton.Name = "SelectInverseCoefficientButton";
            this.SelectInverseCoefficientButton.Size = new System.Drawing.Size(100, 23);
            this.SelectInverseCoefficientButton.TabIndex = 5;
            this.SelectInverseCoefficientButton.Text = "Select Inverse";
            this.SelectInverseCoefficientButton.UseVisualStyleBackColor = true;
            this.SelectInverseCoefficientButton.Click += new System.EventHandler(this.SelectInverseCoefficientButton_Click);
            // 
            // SolutionVectorDisplay
            // 
            this.SolutionVectorDisplay.Enabled = false;
            this.SolutionVectorDisplay.Location = new System.Drawing.Point(349, 31);
            this.SolutionVectorDisplay.Name = "SolutionVectorDisplay";
            this.SolutionVectorDisplay.ReadOnly = true;
            this.SolutionVectorDisplay.Size = new System.Drawing.Size(100, 20);
            this.SolutionVectorDisplay.TabIndex = 4;
            // 
            // InverseCoefficientMatrixDisplay
            // 
            this.InverseCoefficientMatrixDisplay.Enabled = false;
            this.InverseCoefficientMatrixDisplay.Location = new System.Drawing.Point(156, 31);
            this.InverseCoefficientMatrixDisplay.Name = "InverseCoefficientMatrixDisplay";
            this.InverseCoefficientMatrixDisplay.ReadOnly = true;
            this.InverseCoefficientMatrixDisplay.Size = new System.Drawing.Size(100, 20);
            this.InverseCoefficientMatrixDisplay.TabIndex = 3;
            // 
            // SolutionVectorLabel
            // 
            this.SolutionVectorLabel.AutoSize = true;
            this.SolutionVectorLabel.Location = new System.Drawing.Point(265, 34);
            this.SolutionVectorLabel.Name = "SolutionVectorLabel";
            this.SolutionVectorLabel.RightToLeft = System.Windows.Forms.RightToLeft.No;
            this.SolutionVectorLabel.Size = new System.Drawing.Size(78, 13);
            this.SolutionVectorLabel.TabIndex = 1;
            this.SolutionVectorLabel.Text = "Solution vector";
            // 
            // InverseCoefficientMatrixLabel
            // 
            this.InverseCoefficientMatrixLabel.AutoSize = true;
            this.InverseCoefficientMatrixLabel.Location = new System.Drawing.Point(26, 34);
            this.InverseCoefficientMatrixLabel.Name = "InverseCoefficientMatrixLabel";
            this.InverseCoefficientMatrixLabel.Size = new System.Drawing.Size(124, 13);
            this.InverseCoefficientMatrixLabel.TabIndex = 0;
            this.InverseCoefficientMatrixLabel.Text = "Inverse coefficient matrix";
            // 
            // ClearButton
            // 
            this.ClearButton.Location = new System.Drawing.Point(179, 215);
            this.ClearButton.Name = "ClearButton";
            this.ClearButton.Size = new System.Drawing.Size(75, 23);
            this.ClearButton.TabIndex = 2;
            this.ClearButton.Text = "Clear";
            this.ClearButton.UseVisualStyleBackColor = true;
            this.ClearButton.Click += new System.EventHandler(this.ClearButton_Click);
            // 
            // SolveButton
            // 
            this.SolveButton.Location = new System.Drawing.Point(260, 215);
            this.SolveButton.Name = "SolveButton";
            this.SolveButton.Size = new System.Drawing.Size(75, 23);
            this.SolveButton.TabIndex = 3;
            this.SolveButton.Text = "Solve";
            this.SolveButton.UseVisualStyleBackColor = true;
            this.SolveButton.Click += new System.EventHandler(this.SolveButton_Click);
            // 
            // SystemsOfEquationsView
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(496, 250);
            this.Controls.Add(this.SolveButton);
            this.Controls.Add(this.ClearButton);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.groupBox1);
            this.Name = "SystemsOfEquationsView";
            this.Text = "SystemsOfEquationsView";
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.groupBox2.ResumeLayout(false);
            this.groupBox2.PerformLayout();
            this.ResumeLayout(false);

        }
        #endregion

        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.Label AnswerVectorLabel;
        private System.Windows.Forms.Label CoefficientMatrixLabel;
        private System.Windows.Forms.GroupBox groupBox2;
        private System.Windows.Forms.Label SolutionVectorLabel;
        private System.Windows.Forms.Label InverseCoefficientMatrixLabel;
        private System.Windows.Forms.Button ClearButton;
        private System.Windows.Forms.Button SolveButton;
        private System.Windows.Forms.Button SelectAnswerVectorBotton;
        private System.Windows.Forms.Button SelectCoefficientButton;
        private System.Windows.Forms.Button SelectSolutionButton;
        private System.Windows.Forms.Button SelectInverseCoefficientButton;
        private System.Windows.Forms.TextBox AnswerVectorDisplay;
        private System.Windows.Forms.TextBox CoefficientMatrixDisplay;
        private System.Windows.Forms.TextBox SolutionVectorDisplay;
        private System.Windows.Forms.TextBox InverseCoefficientMatrixDisplay;
    }
}

Code I've written for the logic.

//SystemsOfEquationsView.cs
using System;
using System.Drawing;
using System.Windows.Forms;
using XL = Microsoft.Office.Interop.Excel;

namespace ExcelAddIn1.System_Of_Linear_Equations
{
    public partial class SystemsOfEquationsView : Form
    {
        private readonly Color _defaultForeColor = Color.Black;
        private readonly Color _alertForeColor = Color.Red;

        public SystemsOfEquationsView()
        {
            InitializeComponent();
        }

        private void SolveButton_Click(object sender, EventArgs e)
        {
            RestoreDefaultColoring();

            if (AreInputValuesInValid())
            {
                //MessageBox.Show(SystemOfLinearEquations.InvalidInputText, SystemOfLinearEquations.InvalidInputCaption);
                MessageBox.Show("Inputs need to be valid, correct cell references before continuing.", "Invalid input");
                return;
            }

            if (CoefficientMatrix.Rows.Count != CoefficientMatrix.Columns.Count)
            {
                CoefficientMatrixDisplay.ForeColor = Color.Red;
                //MessageBox.Show(SystemOfLinearEquations.NonSquareMatrixText, SystemOfLinearEquations.NonSquareMatrixCaption);
                MessageBox.Show("A non - square matrix cannot be solved for", "Non - square matrix");
                return;
            }

            double matrixDeterminant;
            try
            {
                matrixDeterminant = Globals.ThisAddIn.Application.WorksheetFunction.MDeterm(CoefficientMatrix);
            }
            catch (Exception)
            {
                MessageBox.Show(SystemOfLinearEquations.NonSingularMatrixText, SystemOfLinearEquations.NonSingularMatrixCaption);
                return;
            }

            if (AnswerVector.Rows.Count != CoefficientMatrix.Columns.Count)
            {
                AnswerVectorDisplay.ForeColor = _alertForeColor;
                //MessageBox.Show(SystemOfLinearEquations.AnswerVectorMustMatchCoeffMatrixColumns);
                MessageBox.Show("Answer vector rows must match coefficient matrix columns");
                return;
            }

            if (AnswerVector.Columns.Count != 1)
            {
                AnswerVectorDisplay.ForeColor = _alertForeColor;
                //MessageBox.Show(SystemOfLinearEquations.AnswerVectorSingleColumn);
                MessageBox.Show("A non - square matrix cannot be solved for") ;
                return;
            }

            InverseCoefficientMatrix = InverseCoefficientMatrix.Resize[CoefficientMatrix.Rows.Count, CoefficientMatrix.Columns.Count];
            SolutionVector = SolutionVector.Resize[AnswerVector.Rows.Count, 1];

            if (WillOverwriteInformation(InverseCoefficientMatrix) || WillOverwriteInformation(SolutionVector))
            {
                DialogResult result = MessageBox.Show("Information will be erased if you continue", "Ok to proceed?", MessageBoxButtons.YesNo);
                if (result.Equals(DialogResult.No))
                {
                    return;
                }
            }

            InverseCoefficientMatrix.FormulaArray = $"=minverse({CoefficientMatrix.Address})";
            SolutionVector.FormulaArray = $"=mmult({InverseCoefficientMatrix.Address},{AnswerVector.Address})";
        }

        private void RestoreDefaultColoring()
        {
            CoefficientMatrixLabel.ForeColor = _defaultForeColor;
            AnswerVectorLabel.ForeColor = _defaultForeColor;
            InverseCoefficientMatrixLabel.ForeColor = _defaultForeColor;
            SolutionVectorLabel.ForeColor = _defaultForeColor;
        }

        //TODO convert to static utility class
        private bool WillOverwriteInformation(XL.Range destination, bool checkForConstants = true, bool checkForFormulas = true)
        {
            bool willOverwriteConstants = false;
            bool willOverwriteFormulas = false;

            if (checkForConstants)
            {
                try
                {
                    willOverwriteConstants = destination.SpecialCells(XL.XlCellType.xlCellTypeConstants).Count > 0;
                }
                catch (System.Runtime.InteropServices.COMException e)
                {
                    willOverwriteConstants = false;
                }
            }

            if (checkForFormulas)
            {
                try
                {
                    willOverwriteFormulas = destination.SpecialCells(XL.XlCellType.xlCellTypeFormulas).Count > 0;
                }
                catch (System.Runtime.InteropServices.COMException e)
                {
                    willOverwriteFormulas = false;
                }
            }

            return willOverwriteConstants || willOverwriteFormulas;
        }

        private void ClearButton_Click(object sender, EventArgs e)
        {
            CoefficientMatrixDisplay.Clear();
            AnswerVectorDisplay.Clear();
            InverseCoefficientMatrixDisplay.Clear();
            SolutionVectorDisplay.Clear();

            RestoreDefaultColoring();
        }

        private bool AreInputValuesInValid()
        {
            CoefficientMatrixLabel.ForeColor = CoefficientMatrix is null
                ? _alertForeColor
                : _defaultForeColor;

            AnswerVectorLabel.ForeColor = AnswerVector is null
                ? _alertForeColor
                : _defaultForeColor;

            InverseCoefficientMatrixLabel.ForeColor = InverseCoefficientMatrix is null
                ? _alertForeColor
                : _defaultForeColor;

            SolutionVectorLabel.ForeColor = SolutionVector is null
                ? _alertForeColor
                : _defaultForeColor;

            return CoefficientMatrixLabel.ForeColor.Equals(_alertForeColor)
                || AnswerVectorLabel.Equals(_alertForeColor)
                || InverseCoefficientMatrixLabel.Equals(_alertForeColor)
                || SolutionVectorLabel.Equals(_alertForeColor);
        }

        public XL.Range CoefficientMatrix { get; set; }

        private void SelectCoefficientButton_Click(object sender, EventArgs e)
        {
            Hide();

            dynamic unsafeCoefficientMatrix = Globals.ThisAddIn.Application.InputBox("Select coefficient matrix range", "Coefficient Matrix", Type: 8);
            if (unsafeCoefficientMatrix is XL.Range)
            {
                CoefficientMatrix = unsafeCoefficientMatrix;
                CoefficientMatrixDisplay.Text = CoefficientMatrix.Address[false, false];
            }

            Show();
        }

        public XL.Range AnswerVector { get; set; }

        private void SelectAnswerVectorBotton_Click(object sender, EventArgs e)
        {
            Hide();

            dynamic unsafeRHSVector = Globals.ThisAddIn.Application.InputBox("Select answer vector", "Answer vector", Type: 8);
            if (unsafeRHSVector is XL.Range)
            {
                AnswerVector = unsafeRHSVector;
                AnswerVectorDisplay.Text = AnswerVector.Address[false, false];
            }

            Show();
        }

        public XL.Range InverseCoefficientMatrix { get; set; }

        private void SelectInverseCoefficientButton_Click(object sender, EventArgs e)
        {
            Hide();

            dynamic unsafeInverceCoefficient = Globals.ThisAddIn.Application.InputBox("Select coefficient matrix", "Coefficient matrix", Type: 8);
            if (unsafeInverceCoefficient is XL.Range)
            {
                InverseCoefficientMatrix = unsafeInverceCoefficient;
                InverseCoefficientMatrixDisplay.Text = InverseCoefficientMatrix.Address[false, false];
            }

            Show();
        }

        public XL.Range SolutionVector { get; set; }

        private void SelectSolutionButton_Click(object sender, EventArgs e)
        {
            Hide();

            dynamic unsafeSolutionVector = Globals.ThisAddIn.Application.InputBox("Select solution vector", "Solution vector", Type: 8);
            if (unsafeSolutionVector is XL.Range)
            {
                SolutionVector = unsafeSolutionVector;
                SolutionVectorDisplay.Text = SolutionVector.Address[false, false];
            }

            Show();
        }
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.