我的form1类包含一堆我需要保存的数据,因此一次只能运行一个实例。
public partial class Form1 : Form
{
public string form1string = "I really need to save this data";
public Form1()
{
InitializeComponent();
// Even if I pass my form1 object here I still can't access it from
// the upcoming static methods.
InterceptKeys hook = new InterceptKeys();
}
InterceptKeys不是我的代码,它包含一些键盘钩子所需的静态方法。
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int trueKeyPressed = Marshal.ReadInt32(lParam);
if (Form1.mirror)
{
Form1.newKeyPress(trueKeyPressed);
return (IntPtr)1;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
因为HookCallBack方法是静态的,所以Form1.newKeyPress()也需要是静态的。
但是如果newKeyPress处于静态状态,我无法访问我需要的数据!我不想在这里声明一个新的form1对象,因为这会给我不同版本的数据。正确的吗?
我不是面向对象的专家。我应该如何格式化,以确保所有InterceptKey的form1方法调用都转到我想要的form1对象?
谢谢,如果您需要更多信息,请告诉我们!
答案 0 :(得分:3)
您有两个设计问题:
如何从静态方法调用实例方法
因为HookCallBack方法是 static,Form1.newKeyPress()需要 也是静止的。
您可以将主表单的实例传递给HookCallBack
方法,您只需要在静态方法中添加其他参数:
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam, Form1 form)
{
// ...
}
这实际上是首选策略。只要您的方法和类依赖于其他对象,就应该将依赖项传递给方法,而不是将它们从全局状态中拉出来。
除此之外,您可以遍历Application.OpenForms集合并找到您要查找的表单,如下所示:
var form = Application.OpenForms.OfType<Form1>().First();
form.newKeyPress();
如何一次打开一个表单实例
其他人建议将表单设置为静态 - 这是一种方法,但这是一种糟糕的方法。静态表单在处理时不会被垃圾收集,你必须在显示/隐藏表单时实现自己的init / reset方法,如果静态表单引用了其他对象,那么你的app会慢慢泄漏内存,{{3 }}。我实际上推荐这样的东西:
class FormFactory
{
public Form1 GetForm1()
{
return Application.OpenForms.OfType<Form1>().FirstOrDefault ?? new Form1();
}
}
因此,您的FormFactory控制表单的生命周期,现在您可以使用new FormFactory.GetForm1()
获取Form1的现有或新实例。
答案 1 :(得分:2)
将按键传递给其他表格
在我看来,你基本上只是将按键传递给你的表单,这意味着一种基本的消息通知/观察者模式。也许你只需要一个更好的设计模式。请尝试以下方法:
public class MessageHooks
{
public static event Action<int> OnHookCallback;
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int trueKeyPressed = Marshal.ReadInt32(lParam);
if (OnHookCallBack != null)
{
OnHookCallback(trueKeyPressed);
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
猜猜是什么?现在,您的HookCallBack
方法甚至不需要知道表单的存在。相反,您的表单将自己注册到事件处理程序:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MessageHooks.OnHookCallBack += MessageHooks_OnHookCallBack;
this.FormClosed += (sender, e) => MessageHooks.OnHookCallBack -= MessageHooks_OnHookCallBack; // <--- ALWAYS UNHOOK ON FORM CLOSE
}
void MessageHooks_OnHookCallBack(int keyPressed)
{
// do something with the keypress
}
}
请记住,必须在表单关闭时取消挂起表单事件处理程序,否则表单不会被垃圾收集,并且您将遇到许多奇怪的问题,在非可见表单上引发事件
答案 2 :(得分:1)
根据你所写的内容,我认为这样可行:
在Form1
中,有一个类型为Form1
的静态成员来保存实例:
private static Form1 instance;
在Form1
构造函数中,将此静态成员设置为正在创建的实例:
public Form1()
{
// Existing code
Form1.instance = this;
}
现在,将newKeyPress
设为静态,并使用静态成员查找实际的表单实例:
public static void newKeyPress(int trueKeyPressed)
{
Form1 thisIsTheForm1Instance = Form1.instance;
// Now instance.form1string is the data you want
}
答案 3 :(得分:1)
我认为类似于Form1类:
private static Form1 instance;
public static Form1 Instance
{
get
{
if (instance == null)
{
instance = new Form1();
}
return instance;
}
}
在您使用它们的课程中:
Form1 form1 = Form1.Instance;
将完成这项工作。这将首先检查是否有一个,如果是,它将返回实例,否则它将创建一个,下次它将返回一个。