I'm trying to update my data on a main form whenever I change some option in a secondary form.
每当我更改辅助表单中的某个选项时,我都会尝试在主表单上更新我的数据。
Possible solution:
Make the method public on Form1
(the main form) like this:
在Form1(主窗体)上公开方法如下:
public void updatedata()
{
//data update
}
And then call it on the secondary form:
然后在次要表单上调用它:
Form1.updatedata()
This doesn't work and I believe it's because he is trying to update the Form2
这不起作用,我相信这是因为他正在尝试更新Form2
I'm using partial classes, but I'm not very well versed on them.
我正在使用部分课程,但我对它们并不十分熟悉。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
And the secondary one:
次要的一个:
public partial class formOpConfig : Form
{
private Form1 Opener { get; set; }
public formOpConfig(Form1 opener)
{ //initialize component
}
}
3 个解决方案
#1
I feel like surely there is a duplicate question to match this one. But I have been unable to find it.
我觉得肯定有一个重复的问题来匹配这个。但我一直无法找到它。
Given the code you posted, your attempt probably would have worked had you used Opener.updatedata()
instead of Form1.updatedata()
. But that still would not have been the best solution.
鉴于您发布的代码,如果您使用Opener.updatedata()而不是Form1.updatedata(),您的尝试可能会有效。但那仍然不是最好的解决方案。
Commenter John Saunders is correct, the right way to do this is to declare an event
in formOpConfig
, and then have Form1
subscribe to it. That looks more like this:
评论者John Saunders是正确的,正确的做法是在formOpConfig中声明一个事件,然后让Form1订阅它。看起来更像是这样的:
public partial class formOpConfig : Form
{
public event EventHandler UpdateData;
private void SomethingHappens()
{
// do stuff...
OnUpdateData();
// maybe do other stuff too...
}
private void OnUpdateData()
{
EventHandler handler = UpdateData;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
The above declares an event
, and raises that event (invokes the handlers) at the appropriate time (i.e. when SomethingHappens()
).
上面声明了一个事件,并在适当的时候(即当SomethingHappens()时)引发该事件(调用处理程序)。
public partial class Form1 : Form
{
private void OpenConfigForm()
{
OpenConfigForm opConfig = new formOpConfig();
opConfig.UpdateData += (sender, e) => updatedata();
}
// Note that this method is private...no one else should need to call it
private void updatedata()
{
//data update
}
}
Here, Form1
subscribes to the event when it creates the instance of formOpConfig
(I am assuming Form1
is what creates that instance), and when its handler is invoked, it calls the updatedata()
method you've already written.
这里,Form1在创建formOpConfig实例时订阅该事件(我假设Form1是创建该实例的实例),并且当调用其处理程序时,它调用您已经编写的updatedata()方法。
In this way, the two classes remain decoupled; i.e. they are not actually dependent on each other, more than they need to be (in particular, the formOpConfig
class doesn't need to know anything about Form1
).
通过这种方式,这两个类仍然是分离的;即它们实际上并不相互依赖,超出了它们的需要(特别是,formOpConfig类不需要知道任何关于Form1的内容)。
#2
A good way to do this is to use an Event.
一个好方法是使用一个事件。
This allows you to decouple the forms because they do not even need a reference to each other; basically an event is a way for your second form to tell whoever might be listening (without having to exactly know who) that something of interest happened, and to give them some information about that interesting event that they can use.
这允许您解耦表单,因为它们甚至不需要相互引用;基本上,一个事件是你的第二种形式告诉谁可能正在倾听(无需确切地知道是谁)发生了感兴趣的事情,并向他们提供有关他们可以使用的有趣事件的一些信息。
The linked article will give you much more detail than the below, which is just a quick idea of how to do it; I would recommend working through the tutorial!
链接的文章将为您提供比下面更多的细节,这只是一个如何做的快速的想法;我建议您完成本教程!
The mechanism by which this occurs is that anyone who wants to know about interesting events on Form2
has to subscribe to the corresponding event on Form2
; then whenever Form2
wants to tell its listeners that something has happened, it invokes any event handlers that have been attached to the event.
发生这种情况的机制是,任何想要了解Form2上有趣事件的人都必须订阅Form2上的相应事件;然后,只要Form2想要告诉其侦听器发生了某些事情,它就会调用已附加到事件的任何事件处理程序。
Because an event can have multiple handlers, it's a really excellent way to keep components in your application decoupled.
因为事件可以有多个处理程序,所以这是保持应用程序中的组件分离的非常好的方法。
Quick demo
(note: code below is off top of head so not tested, no error handling, etc.)
(注意:下面的代码不在头顶,所以没有经过测试,没有错误处理等)
First of all, you need to declare a class that can be used to send the interesting data to listening parties. This class has to inherit from System.EventArgs
首先,您需要声明一个可用于将有趣数据发送给听众的类。此类必须从System.EventArgs继承
public class InterestingEventArgs:EventArgs
{
public string AnInterestingFact {get;private set;}
public InterestingEventArgs(string fact)
{
AnInterestingFact =fact;
}
}
It doesn't matter where you declare this as long as it's visible to both Form1
and Form2
.
只要它对Form1和Form2都可见,那么在哪里声明它并不重要。
Next, you have to declare an event on Form2
, it needs to be public and should look like this:
接下来,您必须在Form2上声明一个事件,它必须是公共的,应该如下所示:
public event EventHandler<InterestingEventArgs> SomethingInterestingHappened;
Now you need to decide when you are going to tell interested parties about this event. Let's suppose you have a button on Form2
and you want to raise the event when you click it. So in the Click handler for the button, you might have code like this:
现在你需要决定何时告诉有兴趣的人这个事件。假设您在Form2上有一个按钮,并且您希望在单击它时引发该事件。因此,在按钮的Click处理程序中,您可能具有以下代码:
public void btnRaiseEvent_Clicked(object sender, EventArgs e)
{
var fact= txtFact.Text;
var handler = SomethingInterestingHappened;
if (handler!=null)
{
handler(this,new InterestingEventArgs(fact));
}
}
and finally here is how the code might look from Form1 when you are launching Form2, let's say you click a button on Form1
to launch Form2
:
最后,这里是在启动Form2时代码可能从Form1看起来的样子,假设你单击Form1上的一个按钮来启动Form2:
public void btnShowForm2_Clicked(object sender, EventArgs e)
{
var child = new Form2();
child.SomethingInterestingHappened+=OnSomethingInterestingHappened;
child.Show();
}
Finally you need to write an event handler on Form1
that will be called when the event is raised:
最后,您需要在Form1上编写一个事件处理程序,该事件处理程序将在引发事件时调用:
void OnSomethingInterestingHappened(object sender, InterestingEventArgs e)
{
MessageBox.Show("Did you know? " + e.AnInterestingFact);
}
#3
It looks like you have passed in a reference to a Form1 object in the constructor. Use it:
看起来您已经在构造函数中传递了对Form1对象的引用。用它:
public partial class formOpConfig : Form
{
private Form1 Opener { get; set; }
public formOpConfig(Form1 opener)
{
Opener = opener;
}
private void updateForm1()
{
Opener.updatedata();
}
}
Form1 is a class, not an object. You can say Form1.updatedata() if you make updatedata() a static method of the Form1 class, but that is probably not compatible with the rest of your code.
Form1是一个类,而不是一个对象。如果使updatedata()成为Form1类的静态方法,则可以说Form1.updatedata(),但这可能与其余代码不兼容。
#1
I feel like surely there is a duplicate question to match this one. But I have been unable to find it.
我觉得肯定有一个重复的问题来匹配这个。但我一直无法找到它。
Given the code you posted, your attempt probably would have worked had you used Opener.updatedata()
instead of Form1.updatedata()
. But that still would not have been the best solution.
鉴于您发布的代码,如果您使用Opener.updatedata()而不是Form1.updatedata(),您的尝试可能会有效。但那仍然不是最好的解决方案。
Commenter John Saunders is correct, the right way to do this is to declare an event
in formOpConfig
, and then have Form1
subscribe to it. That looks more like this:
评论者John Saunders是正确的,正确的做法是在formOpConfig中声明一个事件,然后让Form1订阅它。看起来更像是这样的:
public partial class formOpConfig : Form
{
public event EventHandler UpdateData;
private void SomethingHappens()
{
// do stuff...
OnUpdateData();
// maybe do other stuff too...
}
private void OnUpdateData()
{
EventHandler handler = UpdateData;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
The above declares an event
, and raises that event (invokes the handlers) at the appropriate time (i.e. when SomethingHappens()
).
上面声明了一个事件,并在适当的时候(即当SomethingHappens()时)引发该事件(调用处理程序)。
public partial class Form1 : Form
{
private void OpenConfigForm()
{
OpenConfigForm opConfig = new formOpConfig();
opConfig.UpdateData += (sender, e) => updatedata();
}
// Note that this method is private...no one else should need to call it
private void updatedata()
{
//data update
}
}
Here, Form1
subscribes to the event when it creates the instance of formOpConfig
(I am assuming Form1
is what creates that instance), and when its handler is invoked, it calls the updatedata()
method you've already written.
这里,Form1在创建formOpConfig实例时订阅该事件(我假设Form1是创建该实例的实例),并且当调用其处理程序时,它调用您已经编写的updatedata()方法。
In this way, the two classes remain decoupled; i.e. they are not actually dependent on each other, more than they need to be (in particular, the formOpConfig
class doesn't need to know anything about Form1
).
通过这种方式,这两个类仍然是分离的;即它们实际上并不相互依赖,超出了它们的需要(特别是,formOpConfig类不需要知道任何关于Form1的内容)。
#2
A good way to do this is to use an Event.
一个好方法是使用一个事件。
This allows you to decouple the forms because they do not even need a reference to each other; basically an event is a way for your second form to tell whoever might be listening (without having to exactly know who) that something of interest happened, and to give them some information about that interesting event that they can use.
这允许您解耦表单,因为它们甚至不需要相互引用;基本上,一个事件是你的第二种形式告诉谁可能正在倾听(无需确切地知道是谁)发生了感兴趣的事情,并向他们提供有关他们可以使用的有趣事件的一些信息。
The linked article will give you much more detail than the below, which is just a quick idea of how to do it; I would recommend working through the tutorial!
链接的文章将为您提供比下面更多的细节,这只是一个如何做的快速的想法;我建议您完成本教程!
The mechanism by which this occurs is that anyone who wants to know about interesting events on Form2
has to subscribe to the corresponding event on Form2
; then whenever Form2
wants to tell its listeners that something has happened, it invokes any event handlers that have been attached to the event.
发生这种情况的机制是,任何想要了解Form2上有趣事件的人都必须订阅Form2上的相应事件;然后,只要Form2想要告诉其侦听器发生了某些事情,它就会调用已附加到事件的任何事件处理程序。
Because an event can have multiple handlers, it's a really excellent way to keep components in your application decoupled.
因为事件可以有多个处理程序,所以这是保持应用程序中的组件分离的非常好的方法。
Quick demo
(note: code below is off top of head so not tested, no error handling, etc.)
(注意:下面的代码不在头顶,所以没有经过测试,没有错误处理等)
First of all, you need to declare a class that can be used to send the interesting data to listening parties. This class has to inherit from System.EventArgs
首先,您需要声明一个可用于将有趣数据发送给听众的类。此类必须从System.EventArgs继承
public class InterestingEventArgs:EventArgs
{
public string AnInterestingFact {get;private set;}
public InterestingEventArgs(string fact)
{
AnInterestingFact =fact;
}
}
It doesn't matter where you declare this as long as it's visible to both Form1
and Form2
.
只要它对Form1和Form2都可见,那么在哪里声明它并不重要。
Next, you have to declare an event on Form2
, it needs to be public and should look like this:
接下来,您必须在Form2上声明一个事件,它必须是公共的,应该如下所示:
public event EventHandler<InterestingEventArgs> SomethingInterestingHappened;
Now you need to decide when you are going to tell interested parties about this event. Let's suppose you have a button on Form2
and you want to raise the event when you click it. So in the Click handler for the button, you might have code like this:
现在你需要决定何时告诉有兴趣的人这个事件。假设您在Form2上有一个按钮,并且您希望在单击它时引发该事件。因此,在按钮的Click处理程序中,您可能具有以下代码:
public void btnRaiseEvent_Clicked(object sender, EventArgs e)
{
var fact= txtFact.Text;
var handler = SomethingInterestingHappened;
if (handler!=null)
{
handler(this,new InterestingEventArgs(fact));
}
}
and finally here is how the code might look from Form1 when you are launching Form2, let's say you click a button on Form1
to launch Form2
:
最后,这里是在启动Form2时代码可能从Form1看起来的样子,假设你单击Form1上的一个按钮来启动Form2:
public void btnShowForm2_Clicked(object sender, EventArgs e)
{
var child = new Form2();
child.SomethingInterestingHappened+=OnSomethingInterestingHappened;
child.Show();
}
Finally you need to write an event handler on Form1
that will be called when the event is raised:
最后,您需要在Form1上编写一个事件处理程序,该事件处理程序将在引发事件时调用:
void OnSomethingInterestingHappened(object sender, InterestingEventArgs e)
{
MessageBox.Show("Did you know? " + e.AnInterestingFact);
}
#3
It looks like you have passed in a reference to a Form1 object in the constructor. Use it:
看起来您已经在构造函数中传递了对Form1对象的引用。用它:
public partial class formOpConfig : Form
{
private Form1 Opener { get; set; }
public formOpConfig(Form1 opener)
{
Opener = opener;
}
private void updateForm1()
{
Opener.updatedata();
}
}
Form1 is a class, not an object. You can say Form1.updatedata() if you make updatedata() a static method of the Form1 class, but that is probably not compatible with the rest of your code.
Form1是一个类,而不是一个对象。如果使updatedata()成为Form1类的静态方法,则可以说Form1.updatedata(),但这可能与其余代码不兼容。