我总是将表单上的修饰符设置为私有,我不喜欢内部也不公开。
直到现在我曾经像这样调用:
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:(
如果表单没有聚焦,则无效。
答案 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)
假设您只有一个消息循环(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成员与访问.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)
为什么你的表单有很多可以从其他线程调用的入口点?线程封送是否较低(表单的控制器可能有帮助),您不必担心这样的样板代码。