Como faço para propriedades do formulário de acesso com Invoke, mas com o parâmetro objeto em C #?

StackOverflow https://stackoverflow.com/questions/740337

  •  09-09-2019
  •  | 
  •  

Pergunta

Eu não poderia descrever o título da minha pergunta o melhor, me desculpe. Atualmente, eu uso Invoke para acessar as propriedades no meu formulário, ele funciona perfeito, mas eu tenho uma função para cada propriedade, que é bastante não confortável.

    public static void EnableLogin(int enabled)
    {
        var form = Form.ActiveForm as FormMain;
        if (form != null)
            form.EnableLogin = enabled;
    }

    public static void EnableConfirm(int enabled)
    {
        var form = Form.ActiveForm as FormMain;
        if (form != null)
            form.EnableConfirm = enabled;
    }

    public static void EnableRetry(int enabled)
    {
        var form = Form.ActiveForm as FormMain;
        if (form != null)
            form.EnableRetry = enabled;
    }

    public static void EnableTABLogin(int enabled)
    {
        var form = Form.ActiveForm as FormMain;
        if (form != null)
            form.EnableTABLogin = enabled;
    }

Cada uma destas funções parece com o

    public int EnableLogin
    {
        set
        {
            if (this.InvokeRequired)
            {
                this.Invoke((MethodInvoker)delegate
                {
                    if (value == 0)
                        this.btnLogin.Enabled = false;
                    else
                        this.btnLogin.Enabled = true;
                });
            }
            else
            {
                if (value == 0)
                    this.btnLogin.Enabled = false;
                else
                    this.btnLogin.Enabled = true;
            }
        }
    }

A minha pergunta é, eu não posso fazê-lo assim

    public static void EnableObject(object name)
    {
        var form = Form.ActiveForm as FormMain;
        if (form != null)
            form.Enable + name = enabled;
    }

Não é definitivamente dessa forma, eu não conseguia pensar em algo mais OO, mas em vez de escrever toneladas de funções com o mesmo código, não consigo usar uma passando o objeto que eu gostaria de mudar?

Foi útil?

Solução

Você pode criar um método que leva um delegado parâmetro que descreve a ação a ser executada. Então você pode se livrar do código repetido.

Aqui está um exemplo: eu crio um método público chamado PerformAction no meu formulário. É preciso um Action delegado como argumento; este delegado descreve a ação que deve ser tomada.

O método de instância deve ser usada quando possível, mas para ser completo eu criei uma versão estática que recebe a instância do formulário a partir Form.ActiveForm.

Os olhares código como este:

using System;
using System.Windows.Forms;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        public void PerformAction(Action<MainForm> action)
        {
            if (InvokeRequired)
                Invoke(action,this);
            else
                action(this);
        }

        public static void PerformActionOnMainForm(Action<MainForm> action)
        {
            var form = ActiveForm as MainForm;
            if ( form!= null)
                form.PerformAction(action);
        }
    }
}

E pode então ser usado como este de outro segmento:

    MainForm.PerformActionOnMainForm(form => form.Text = "My form");
    // The action can also be a code block or a method:
    MainForm.PerformActionOnMainForm(form =>
                                         {
                                             form.Width = 200;
                                             form.Height = 300;
                                             form.Left = 100;
                                             form.Top = 200;
                                         });

PerformAction poderia também ser feita genérico para que você possa usá-lo em qualquer de suas formas. Em seguida, a assinatura seria:

public void PerformAction<T>(Action<T> action) 
    where T : Form 
    { 
        ... 
    }

Não faria sentido declará-la como esta se você tem uma classe base comum que é compartilhado entre seus formulários. Alternativamente, você pode criar uma classe auxiliar que contém o método.

Outras dicas

Eu fiz uma pergunta semelhante , mas para WPF, o princípio é o mesmo embora. Modificando a resposta que foi dada a mim por Jon Skeet para sua pergunta você poderia usar algo como isto:

public static void InvokeIfNecessary(Form form, MethodInvoker action)
{    
     if (form.InvokeRequired)    
     {        
          form.Invoke(DispatcherPriority.Normal, action);    
     }    
     else    
     {        
          action();    
     }
}

public static void EnableLogin(int enabled)    
{        
    var form = Form.ActiveForm as FormMain;        
    if (form != null)            
        InvokeIfNecessary(form, delegate { form.btnLogin.Enabled = (enabled != 0) });    
}

Edit:. Mudou de usar form.Dispatcher

Você pode mover a funcionalidade reutilizado em dois métodos estáticos Sperate (um ramal), que irá simplificar muito o que você tem nas ajudantes estáticos e propriedades.

public static class FormHelpers
{
  public static void InvokeOnActive<TForm>(Action<TForm> action)
    where TForm : Form
  {
    TForm activeForm = Form.ActiveForm as TForm;
    if (activeForm != null)
      activeForm.InvokeEx(f => { action(f); return f; });
  }
}

public static class ControlExtensions
{
  public static TResult InvokeEx<TControl, TResult>(this TControl control,
                                              Func<TControl, TResult> func)
    where TControl : Control
  {
    if (control.InvokeRequired)
      return (TResult)control.Invoke(func, control);
    else
      return func(control);
  }
}

E para as suas propriedades:

public int EnableLogin
{
  set { this.InvokeEx(f => f.btnLogin.Enabled = value == 0); }
}

E para seus ajudantes estáticos:

public static void EnableLogin(int enabled)
{
  FormHelpers.InvokeOnActive<FormMain>(f => f.EnableLogin = enabled);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top