如何用动作调用?

时间:2009-04-28 15:09:30

标签: c# winforms invoke

我总是将表单上的修饰符设置为私有,我不喜欢内部也不公开。

直到现在我曾经像这样调用:

public string Addtext
{
    if(InvokeRequired)
    {
         Invoke((MethodInvoker)delegate
         {
             textbox.text = value;
         });
    }
    else
        textbox.text = value;
}

但是为我表单上的每个成员添加这样的属性根本不是面向对象的。

我想创建一个调用参数(动作)的函数。我尽力了,但我失败了 - 它要求表单成员公开内部 :(

    public void PerformActionOnForm(Action<FormMain> action)
    {
        var form = Form.ActiveForm as FormMain;
        object s = action.Clone();
        if (form != null)
        {
            form.PerformAction(action);
        }
    }

    public void PerformAction(Action<FormMain> action)
    {
        if (InvokeRequired)
            Invoke(action, this);
        else
            action(this);
    }

我的代码中有两个问题:

它需要我想改变的属性!= private:(

如果表单没有聚焦,则无效。

3 个答案:

答案 0 :(得分:2)

以什么方式为需要访问或设置在“不面向对象”的表单范围之外的数据添加属性?这是你唯一的选择。匿名委托(或任何委托,代码)中的代码在声明它的上下文中执行。唯一能够解决可见性问题的工具就是反思,那就是臭臭味道。创建属性并根据需要使用它们。

至于你的第二个选项,我假设你想在你的“主表格”上执行此选项。这里有两个选项:假设只有一个实例并将其保留为类的静态属性,并在实例构造函数中指定它。

public partial class MainForm : Form
{
    private static MainForm singletonInstance;

    public static MainForm SingletonInstance
    {
        get { return singletonInstance; }
    }

    public MainForm() : base()
    {
        InitializeComponent();

        singletonInstance = this;
    }
}

public void PerformActionOnForm(Action<FormMain> action)
{
    var form = MainForm.SingletonInstance;
    // object s = action.Clone(); What was this for?
    if (form != null)
    {
        form.PerformAction(action);
    }
}

另一个只有在您的所有表单都被“拥有”并且唯一没有所有者的表单是您的主要表单时才有效。在那种情况下,你可以这样做:

public void PerformActionOnForm(Action<FormMain> action)
{
    var form = Form.ActiveForm.TopLevelControl as FormMain;
    // object s = action.Clone(); What was this for?
    if (form != null)
    {
        form.PerformAction(action);
    }
}

答案 1 :(得分:1)

从非UI线程调用UI组件

假设您只有一个消息循环(99%就是这种情况),那么:

public static class SynchronizedInvoker
{
    public static void Invoke(Action action)
    {
        Form form = Application.OpenForms.Cast<Form>().FirstOrDefault();
        if (form != null && form.InvokeRequired)
            form.Invoke(action);
        else
            action();
    }
}

调用代码:

SynchronizedInvoker.Invoke(() => myForm.Text = myText);

访问私有UI组件

访问私有UI成员与访问.NET对象的其他私有成员没有什么不同。私有成员的性质是不能从其他对象访问。如果您仍想访问,则必须将UI组件的引用传递给调用者,或者使用反射来解析私有对象的路径。

将UI组件的引用传递给调用者的示例:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(delegate { MyWorker.Run(button1); }); 
    }
}

class MyWorker
{
    public static void Run(Button button)
    {
        SynchronizedInvoker.Invoke(() => button.Text = "running");
        Thread.Sleep(5000); // do some important work here
        SynchronizedInvoker.Invoke(() => button.Text = "finished");
    }
}

使用反射在技术上是可行的,但并不理想。您需要知道私有成员的路径,并且需要有关对象内部的信息。然后,您应该问自己为什么首先将其设为私有。

答案 2 :(得分:0)

为什么你的表单有很多可以从其他线程调用的入口点?线程封送是否较低(表单的控制器可能有帮助),您不必担心这样的样板代码。