Как вызвать метод экземпляра из статического метода другого класса (т. Е. Иметь только один объект)? - PullRequest
1 голос
/ 15 января 2010

мой класс 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 в static, я не могу получить доступ к нужным мне данным!Я не хотел бы объявлять новый объект form1 здесь, поскольку это дало бы мне разные версии данных.Правильно?

Я не объектно-ориентированный эксперт.Как мне отформатировать это, чтобы убедиться, что все вызовы метода InterceptKey form1 идут к нужному мне объекту form1?

Спасибо, пожалуйста, дайте мне знать, если вам нужна дополнительная информация!

Ответы [ 4 ]

3 голосов
/ 15 января 2010

У вас есть две проблемы с дизайном:

Как вызвать метод экземпляра из статического метода

Поскольку метод 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, когда вы показываете / скрываете форму, если статическая форма имеет ссылки на другие объекты, ваше приложение будет медленно пропускать память, среди прочего . Я действительно рекомендую что-то вроде этого:

class FormFactory
{
    public Form1 GetForm1()
    {
        return Application.OpenForms.OfType<Form1>().FirstOrDefault ?? new Form1();
    }
}

Таким образом, ваш FormFactory контролирует время жизни вашей формы, теперь вы можете получить существующий или новый экземпляр Form1, используя new FormFactory.GetForm1().

2 голосов
/ 15 января 2010

Передача нажатий клавиш в другие формы

Мне приходит в голову, что вы в основном просто передаете нажатия клавиш в форму, что подразумевает своего рода базовый шаблон уведомления / сообщения. Может быть, вам просто нужен лучший дизайн шаблона. Попробуйте следующее:

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

Помните, вы должны отцепить обработчик событий формы при закрытии формы, иначе форма не будет собирать мусор, и вы столкнетесь с множеством странных проблем, вызывающих события в невидимых формах.

1 голос
/ 15 января 2010

Я думаю, что-то вроде того, что в классе Form1:

private static Form1 instance;


 public static Form1 Instance
 {
      get
      {
          if (instance == null)
          {
              instance = new Form1();
          }
          return instance;
      }
 }

И в ваших классах, которые их используют:

Form1 form1 = Form1.Instance;

Сделаю работу. Сначала он проверит, есть ли он, в таком случае он вернет экземпляр, в противном случае он создаст его, и в следующий раз вернет один.

1 голос
/ 15 января 2010

Из того, что вы написали, я думаю, что это будет работать:

В 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...