如何使用Invoke访问表单属性,但在C#中使用object参数?

时间:2022-12-30 07:21:28

I couldn't describe the title of my question the best,I'm sorry. Currently,I use Invoke to access the properties on my form,It works perfect,but I have a function for each property,which is quite not comfortable.

我无法用最好的方式描述我的问题的标题,对不起。目前,我使用Invoke访问我的表单上的属性,它工作得很完美,但我有一个功能,每个属性,这是非常不舒服。

    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;
    }

Each of these functions looks like that

这些功能中的每一个都是这样的

    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;
            }
        }
    }

My question is,can't I do it like that

我的问题是,我不能那样做

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

It's definitely not that way,I couldn't think of something more OO,but instead of writing tons of functions with same code,can't I use one by passing the object I'd like to change?

这绝对不是那种方式,我想不出更多的OO,但不是用相同的代码编写大量的函数,我不能通过传递我想改变的对象来使用它吗?

3 个解决方案

#1


You could create a method that takes an delegate parameter describing the action to perform. Then you could get rid of the repeated code.

您可以创建一个方法,该方法接受描述要执行的操作的委托参数。然后你可以摆脱重复的代码。

Here is an example: I create a public method called PerformAction on my form. It takes an Action<MainForm> delegate as argument; this delegate describes the action that should be taken.

这是一个例子:我在表单上创建一个名为PerformAction的公共方法。它需要一个Action 委托作为参数;该代表描述了应该采取的行动。

The instance method should be used when possible, but for completeness I created a static version that gets the Form instance from Form.ActiveForm.

应尽可能使用实例方法,但为了完整性,我创建了一个静态版本,从Form.ActiveForm获取Form实例。

The code looks like this:

代码如下所示:

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);
        }
    }
}

And can then be used like this from another thread:

然后可以从另一个线程这样使用:

    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 could also be made generic so you can use it on any of your forms. Then the signature would be:

PerformAction也可以是通用的,因此您可以在任何表单上使用它。然后签名将是:

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

It would make sense to declare it like this if you have a common base class that is shared amongst your forms. Alternatively, you could create a helper class containing the method.

如果你有一个在表单*享的公共基类,那么将它声明为这样是有意义的。或者,您可以创建包含该方法的帮助程序类。

#2


I asked a similar question but for WPF, the principle is the same though. Modifying the answer that was provided to me by Jon skeet for your question you could use something like this:

我问了一个类似的问题但是对于WPF来说,原则是相同的。修改Jon skeet为您提出的答案,您可以使用以下内容:

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: Changed from using form.Dispatcher.

编辑:更改为使用form.Dispatcher。

#3


You can move the reused functionality into two sperate static methods (one extension) which will greatly simplify what you have in the static helpers and properties.

您可以将重用的功能移动到两个sperate静态方法(一个扩展)中,这将大大简化您在静态助手和属性中的功能。

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);
  }
}

And for your properties:

并为您的财产:

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

And for your static helpers:

对于你的静态助手:

public static void EnableLogin(int enabled)
{
  FormHelpers.InvokeOnActive<FormMain>(f => f.EnableLogin = enabled);
}

#1


You could create a method that takes an delegate parameter describing the action to perform. Then you could get rid of the repeated code.

您可以创建一个方法,该方法接受描述要执行的操作的委托参数。然后你可以摆脱重复的代码。

Here is an example: I create a public method called PerformAction on my form. It takes an Action<MainForm> delegate as argument; this delegate describes the action that should be taken.

这是一个例子:我在表单上创建一个名为PerformAction的公共方法。它需要一个Action 委托作为参数;该代表描述了应该采取的行动。

The instance method should be used when possible, but for completeness I created a static version that gets the Form instance from Form.ActiveForm.

应尽可能使用实例方法,但为了完整性,我创建了一个静态版本,从Form.ActiveForm获取Form实例。

The code looks like this:

代码如下所示:

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);
        }
    }
}

And can then be used like this from another thread:

然后可以从另一个线程这样使用:

    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 could also be made generic so you can use it on any of your forms. Then the signature would be:

PerformAction也可以是通用的,因此您可以在任何表单上使用它。然后签名将是:

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

It would make sense to declare it like this if you have a common base class that is shared amongst your forms. Alternatively, you could create a helper class containing the method.

如果你有一个在表单*享的公共基类,那么将它声明为这样是有意义的。或者,您可以创建包含该方法的帮助程序类。

#2


I asked a similar question but for WPF, the principle is the same though. Modifying the answer that was provided to me by Jon skeet for your question you could use something like this:

我问了一个类似的问题但是对于WPF来说,原则是相同的。修改Jon skeet为您提出的答案,您可以使用以下内容:

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: Changed from using form.Dispatcher.

编辑:更改为使用form.Dispatcher。

#3


You can move the reused functionality into two sperate static methods (one extension) which will greatly simplify what you have in the static helpers and properties.

您可以将重用的功能移动到两个sperate静态方法(一个扩展)中,这将大大简化您在静态助手和属性中的功能。

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);
  }
}

And for your properties:

并为您的财产:

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

And for your static helpers:

对于你的静态助手:

public static void EnableLogin(int enabled)
{
  FormHelpers.InvokeOnActive<FormMain>(f => f.EnableLogin = enabled);
}