2013-05-29 5 views
1

Я пытаюсь вызвать функцию в основной форме из другой формы ... Уже получил вызов простой функции, объявив ее публичной статикой в ​​основной форме, но я могу «Назови нужный. Функция для вызова:C# - вызов функции в родительской форме

public static void spotcall() 
    { 
     string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString(); 
     MainForm.txtSendKeys.Text = dial;// Here it asks me for a reference to an object. 


     foreach (char c in txtSendKeys.Text) 
     { 
      sideapp.Keyboard.SendKey(c.ToString(), checkBoxPrivate.Checked); 
     } 
     txtSendKeys.Clear(); 
    } 

Процедура Я использую, чтобы вызвать его из формы ребенка:

private void button1_Click(object sender, EventArgs e) 
    { 
     button1.Text = "Hoho"; 
     MainForm.spotcall(); 
    } 

Я полностью признаю, что мне не хватает какой-то теории о C#, но, как это часто бывает, я просто нужно сделать это для моей работы, поэтому я надеюсь получить помощь, если случайно я не получу решение самостоятельно. Спасибо :)

+0

Можете ли вы дать нам сообщение об ошибке вы получаете? Это не компиляция, верно? Что компилятор говорит? –

+0

Он запрашивает меня и ссылается на объекты для «txtSendKeys». Сообщение на французском языке, поэтому вы не можете получить точный текст. –

ответ

1

Я думаю, что правильный способ сделать это - использовать делегаты. Таким образом, ваша форма (окно) не должна ничего знать о родительской форме (форма может быть открыта из разных родительских форм).

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

В верхней части формы ребенка создать делегат:

public delegate void CloseEvent(); 
    public CloseEvent WindowClosed; 

Создать событие формы закрытия и его называют свой делегат:

private void child_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     WindowClosed(); 
    } 

кнопку в родительской форме может показать ребенка и установить обратный вызов:

private ChildForm childform = null; 

    private void buttonShowChildForm_Click(object sender, EventArgs e) 
    { 
     if (childform == null) 
     { 
     childform = new ChildForm(); 
     childform.WindowClosed += childClosed; 
     childform.Show(); 
     } else 
     { 
     childform.BringToFront(); 
     } 
    } 

    private void childClosed() 
    { 
     childform = null; 
    } 

В этом примере мы используем кнопку для открытия новая форма, которая не блокирует родительскую форму. Если пользователь пытается открыть форму во второй раз, мы просто приносим существующую форму на передний план, чтобы показать ее пользователю. Когда форма закрыта, мы устанавливаем объект в null, чтобы в следующий раз, когда мы нажимаем кнопку, открывается новая форма, потому что старый был удален при закрытии.

С наилучшими пожеланиями Hans Фрезерная ...

0

Вы можете поместить общий код в третий класс, который является видимым для обеих форм. Так, например:

public class static HelperFunctions 
{ 

    public static void spotcall() 
    { 
     . . . 
    } 
} 

Затем замените

MainForm.spotcall() 

с

HelperFunctions.spotcall() 
1

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

Для того чтобы spotcall был статическим, вам необходимо удалить ссылку на txtSendKeys (я предполагаю, что это текстовое поле, которое вы создали в другом месте в форме), или txtSendKeys должны быть объявлены в статической функции ,

Дополнительно:

Вы получили значение для txtSendKeys.Text в предыдущей строке, с помощью переменного набора. Вместо того, чтобы ссылаться на txtSendKeys.Text вообще, я думаю, вы могли бы просто использовать диск с переменной для завершения функции и оставить функцию static (вы все равно очищаете ее в конце).

public static void spotcall() 
    { 
     string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString(); 


     foreach (char c in dial) 
     { 
      sideapp.Keyboard.SendKey(c.ToString(), checkBoxPrivate.Checked); 
     }    
    } 

Хотя, это не позволило бы преодолеть ту же проблему, с которой вы, вероятно, столкнулись бы с checkBoxPrivate.Checked.

Вы можете изменить его, чтобы получить логический аргумент.

public static void spotcall(Boolean PrivateChecked) 
    { 
     string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString();    

     foreach (char c in dial) 
     { 
      sideapp.Keyboard.SendKey(c.ToString(), PrivateChecked); 
     } 

    } 
+2

Думаю, ему нужно обратное: spotcall() должен быть методом экземпляра. txtSendKeys, вероятно, является свойством, связанным с элементом управления, созданным в конструкторе форм. Он не может заявить об этом в другом месте, и он не может сделать ничего полезного без него. Ему просто нужно получить экземпляр MainForm в том месте, где он называет spotcall(). –

+1

Я не согласен, почтительно. Он получил значение для txtSendKeys.Text в предыдущей строке с помощью переключателя. Вместо того, чтобы ссылаться на txtSendKeys.Text вообще, я полагаю, он мог просто использовать диск с переменной для завершения функции и оставить функцию static (он все равно очищает ее в конце). Хотя, это не позволило бы преодолеть ту же проблему, что он, скорее всего, столкнулся с checkBoxPrivate.Checked ... но, надеюсь, решение этой проблемы приведет его к решению этого вопроса. – Chris

+0

О, я понимаю, что вы имеете в виду. Я не уделял достаточного внимания тому, что на самом деле делал его код. Вы совершенно правы, txtSendKeys вообще не принадлежит. Он использует элемент пользовательского интерфейса как избыточную временную переменную. Все, что он действительно делает, отправляет значение ключа реестра где-то еще. Спасибо за несогласие гораздо более уважительно, чем я на самом деле заслужил! :) –

1

Вы не можете получить доступ к нестатическим членам в статическом контексте, что означает, что вы должны из txtSendKeys статическом, или сделать вашу функцию нестатической.

0

MainForm - это просто класс. Он имеет структуру класса. Но единственными данными, которые вы можете получить от него, являются данные static.

Но instance этого класса появляется, когда вы делаете: MainForm MyFormInstance = new MainForm();

MainForm может быть использован только для доступа статические члены (методы, свойства ...). Если вы хотите получить txtSendKeys, вы должны получить его из экземпляра (ссылка на объект). Это потому, что текстовое поле не является статическим, поэтому оно существует только в экземплярах формы.

Таким образом, вы должны сделать следующее:

  • Сделать spotcall не статична.
  • Вставить дочерний элемент в переменную MainForm MyParentMainForm;
  • Когда вы вызываете дочерний элемент, установите MyParentMainForm с экземпляром основной формы. Если он вызывается из основной формы, вы можете получить экземпляр с ключевым словом this.
  • Внутри формы ребенка, звоните MyParentMainForm.spotcall

PS: Я не уверен, если есть что-то вроде реальной форме ребенка или если вы просто вызываете новые формы от другой. Если есть действительно форма child, вы можете получить свойство Parent, чтобы получить доступ к экземпляру основной формы.

5

Вы не можете ссылаться на экземпляры элементов управления на вашем MainForm в статическом методе. Как компилятор говорит вам, вам нужен экземпляр формы для обновления таких вещей, как TextBoxes. Без экземпляра, куда будут перемещаться значения, которые вы пытаетесь обновить?

Я не уверен точно, как создается дочерняя форма, но одним из способов, который вы могли бы назвать методы на вашем MainForm, было бы предоставление ссылки на ваш экземпляр MainForm непосредственно на дочернюю форму. Это может быть через конструктор или некоторую государственную собственность.

Например

public class ChildForm : Form { 

    public MainForm MyParent { get; set; } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     button1.Text = "Hoho"; 

     // Now your child can access the instance of MainForm directly 
     this.MyParent.spotcall(); 
    } 

} 

Предполагая, что вы создаете ChildForm внутри MainForm код, чтобы дать ребенку ссылку довольно прост:

var childForm = new ChildForm(); 
childForm.MyParent = this; // this is a `MainForm` in this case 
childForm.Show(); 

Вы также должны сделать spotcall в экземпляр, а не статический метод, и удалите статическую ссылку на MainForm в вашем коде:

public void spotcall() 
{ 
    string dial = Registry.CurrentUser.OpenSubKey("SOFTWARE").OpenSubKey("INTERCOMCS").GetValue("DIAL").ToString(); 
    // Now it no longer asks you for a reference, you have one! 
    txtSendKeys.Text = dial; 

    foreach (char c in txtSendKeys.Text) 
    { 
     sideapp.Keyboard.SendKey(c.ToString(), checkBoxPrivate.Checked); 
    } 
    txtSendKeys.Clear(); 
} 
0

Это своего рода проблема с «шаблоном проектирования», о которой я расскажу, но я могу попытаться объяснить самый прямой способ решить эту проблему, если вы не ожидаете, что эта программа сильно изменится. «Статические» вещи существуют только один раз - один раз во всем приложении. Когда переменная или функция статична, гораздо проще получить доступ из любой точки программы; но вы не можете получить доступ к связанным с объектом данным, потому что вы не указываете на конкретный экземпляр этого объекта (т. е. у вас есть семь MainForms. На какой из них вы вызываете эту функцию?) Поскольку стандартный дизайн WinForm предполагает, что вы можете семь копий отображения MainForm, все связанные с ними переменные будут экземпляром переменными или нестационарными. Однако, если вы ожидаете, что у вас не будет второго MainForm, вы можете использовать подход «singleton» и иметь простой способ доступа к вашему одному экземпляру.

partial class MainForm { 

    // only including the code that I'm adding; I'm sure there's a lot of stuff in your form. 
    public static MainForm Instance { public get; private set; } 

    protected void onInitialize() { // You need to hook this part up yourself. 
     Instance = this; 
    } 
} 

partial class SubForm { 
    protected void onImportantButton() { 
     MainForm.Instance.doImportantThing() 
    } 
} 

Включение слишком активной логики смены данных в классы форм - довольно распространенная проблема с кодом многих новичков. Это не ужасно - вы не хотели бы делать 5 контрольных классов просто для простой вещи, которую вы пытаетесь.По мере того как код становится более сложным, вы начинаете находить некоторые вещи, имеющим смысл переходить на «подуровень» классов, которые не взаимодействуют с пользователем (поэтому, когда-нибудь, если он будет перекодирован как серверная программа , вы можете выбросить классы форм и просто использовать логические классы - теоретически). Для многих программистов требуется некоторое время, чтобы понять всю концепцию «экземпляров» объекта и «контекст», в котором вызывается функция.

+0

Это ужасная практика, которая приведет к распространению плохой конструкции и сделает ее намного труднее для людей, чтобы научиться правильно * решать эту проблему. – Servy

+0

Когда начинающий учится на работе, хотя ожидается, что он быстро напишет код с фактическим использованием, почти наверняка, что он не будет писать правильный дизайн в первые несколько раз; в некотором смысле, я думаю, что более важно позволить людям сделать простые ошибки шаблона дизайна на ранней стадии, чтобы они могли лучше понимать шаблоны, когда они пишут более поздние программы. Но просить кого-то полностью переписать программу, которую они написали быстро для своей работы, - это настоящая путаница. Тем не менее, я убежден, что это небольшая программа, которая никогда не будет увеличиваться. – Katana314

+0

Большое спасибо за ваш совет. Тем не менее, хотя моя часть кода является чем-то действительно базовым, я на самом деле намерен добавить функциональную значимость в огромную вещь, это, в сущности, SDK стороннего приложения, которое я не могу поставить в обратном порядке;) Btw, это очень плохой результат. –

Смежные вопросы