0

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

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

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 :(

如果表格不在焦点上,则不起作用。

4

3 回答 3

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);
    }
}
于 2009-04-28T15:14:47.723 回答
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");
    }
}

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

于 2009-04-28T16:49:55.810 回答
0

为什么你的表单有这么多可能的入口点,可以从其他线程调用?将线程编组降低(您的表单的控制器可能会有所帮助),您不必担心像这样的样板代码。

于 2009-04-28T15:48:42.527 回答