C# - Windows Forms : Separar a UI da lógica de negócio


Hoje veremos como podemos separar o código da interface do usuário do código da lógica de negócio em uma aplicação Windows Forms.

Existem muitas abordagens que podemos usar para separar o código da interface da lógica de negócio em aplicações Windows Forms, talvez a mais conhecida seja usar o padrão MVVM - Model-View-ViewModel.

Vejamos um exemplo bem simples que será nosso ponto de partida e partir do qual iremos aplicar a separação do código da interface.

Vamos supor que temos uma aplicação Windows Forms (.NET Framework) que contenha um único formulário que por sua vez contém um TextBox e um Button:

Ao executar o projeto o usuário deve informar um número inteiro no TextBox e clicar no botão.

O programa deverá adicionar 10 ao número e atualizar o TextBox com o novo valor.

A lógica de negócio é definida pelo código na classe Processar :

public class Processar
{
     public int AdicionarDez(int numero)
     {
             return numero + 10;
     }
}

Esta lógica não deverá ter conhecimento da UI.

Dessa forma:

  1. Quando o usuário clicar no Button o método AdicionarDez deverá ser invocado;
  2. O TextBox deverá ser atualizado com o retorno do método AdicionarDez;

Para resolver isso você pode definir no evento Click do Button o código abaixo:

 private void button1_Click(object sender, EventArgs e)
 {
            var processo = new Processar();
            var numero = Convert.ToInt32(textBox1.Text);
            var valorCalculado = processo.AdicionarDez(numero);
            textBox1.Text = valorCalculado.ToString();
 }

Muito bem, só que podemos fazer muito melhor do que isso, pois ainda temos no formulário no evento Click do botão uma referência à nossa classe de negócio Processar().

Veremos a seguir uma abordagem onde vamos separar totalmente a lógica do formulário.

Vamos criar uma classe base ProcessarBase que vai conter o button e o textbox e vai gerenciar o evento Click.

using System;
namespace WF_Separa2
{
    public class ProcessarBase
    {
        System.Windows.Forms.Button meuButton;
        public System.Windows.Forms.Button MeuButton
        {
            get
            {
                return meuButton;
            }
            set
            {
                meuButton = value;
                meuButton.Click += new System.EventHandler(this.MeuButton_Click);
            }
        }
        System.Windows.Forms.TextBox meuTextBox;
        public System.Windows.Forms.TextBox MeuTextBox
        {
            get
            {
                return meuTextBox;
            }
            set
            {
                meuTextBox = value;
            }
        }
        public ProcessarBase()
        {
        }
        public virtual void MeuButton_Click(object sender, EventArgs e)
        {
        }
    }
}

Agora a nossa a classe Processar onde esta a nossa lógica de negócio vai herdar desta classe e implementar o evento Click e utilizar as propriedades MeuTextBox e MeuButton e realizar a operação desejada.

using System;
namespace WF_Separa2
{
    public class Processar : ProcessarBase
    {
        public override void MeuButton_Click(object sender, EventArgs e)
        {
            var numero = Convert.ToInt32(MeuTextBox.Text);
            var valorCalculado = AdicionarDez(numero);
            MeuTextBox.Text = valorCalculado.ToString();
        }
        public int AdicionarDez(int numero)
        {
            return numero + 10;
        }
    }
}

Finalmente no formulário Form1 só precisamos criar a instância da nossa classe Processar e atribuir o button1 e textBox1 às nossas propriedades:

using System.Windows.Forms;
namespace WF_Separa2
{
    public partial class Form1 : Form
    {
        Processar processamento = null;
        public Form1()
        {
            InitializeComponent();
            processamento = new Processar
            {
                MeuButton = button1,
                MeuTextBox = textBox1
            };
        }
    }
}

O código agora ficou bem mais limpo.

Podemos ainda fazer a injeção da dependência da classe Processar usando um framework de DI.(fica como exercício)

Pegue o projeto completo aqui:   WF_Separa1.zip

"(Disse Jesus) - Quem ama a sua vida perdê-la-á, e quem neste mundo odeia a sua vida, guardá-la-á para a vida eterna."
João 12:25

Referências:


José Carlos Macoratti