在父表单中调用方法并在c#中以父表单访问gui元素的最佳实践

我正在开发一个win form应用程序,我发现自己经常要求访问我的父表单中的方法,说Form1来自另一个类,无论是表单类还是只是一个类。 我在表单1的构造函数中有一些初始化器,因此我无法创建Form1的实例。 所以我无法访问Form1的方法。

所以我觉得这是一个不好的做法。 但是,在某些情况下,我不知道还有什么可以做,例如考虑这种情况。 我有一个名为ProcessData的类,其中我有一个接收文件的方法,逐行读取并处理数据。 现在我将此方法作为主要表单Form1中的一个线程调用。 我的要求是作为数据处理我想在主窗体Form1中的多行文本框中显示当前正在处理的行。

以前我所做的就是我在同一个Form1中拥有所有内容,所以我使用了一个委托,就像

delegate void SetTextCallback(string text, Control ctrl); private void SetText(string text, Control ctrl) { if (ctrl.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text, ctrl }); } else { if (ctrl.GetType() == typeof(Label)) { ctrl.Text = text; } else { ctrl.Text += Environment.NewLine + text; } } } 

我像SetText(“text”,Label1)一样调用它;

但是如果我从另一个类中调用它来引用Label1,我将需要一个Form1的实例,但是我将无法创建它,那么最佳做法是什么呢?

(我知道我可以将文本传递给SetText并在那里处理控件但我会对从不同类调用的各种文本框和标签控件使用同样的东西)

我通常这样做的方式是让子窗体公开与该窗体上的逻辑操作和事件相对应的事件,例如:

 ///  /// Occurrs when an item is selected in the form ///  public event EventHandler ItemSelected; ///  /// Fires the  event ///  protected void OnItemSelected(MyItem item) { var handler = this.ItemSelected; if (handler != null) { ItemSelectedEventArgs args = new ItemSelectedEventArgs(); args.Item = item; // For example handler(this, args); } } 

我们的想法是,您的父表单的逻辑应该响应您的子表单上的操作,而不是您的子表单上的操作在父表单上执行操作 – 您应该尝试尽可能地封装表单逻辑(也就是关注点的分离) )。

另外作为模式,它应该是父/调用表单,它通过InvokeRequired等处理调用调用到正确线程的调用…而不是子表单 – 除非你在后台线程上工作,否则这将是不必要的。

你的class级应该举起活动,你的表格应该有活动处理程序。 这样可以将表单代码保存在表单中,并将类代码保存在类中。 很好,很整洁。

根据Kragen和Richard的建议,提升事件会起作用,并阻止父/子关系紧密耦合,但如果你想要一些非常灵活的东西,请查看Event Aggregator模式。 Prism项目中提供了一个很好的,虽然很多人发现它使用起来不方便,并且已经创建了扩展,以便更容易使用这样的,或者从头开始编写自己的这些 。

基本上,这个想法是父母甚至不关心消息来自它的子窗口。 子窗口只是在消息总线上抛出了诸如“Open Order#6”之类的消息,假设其他人将处理它,与提出事件几乎相同。 在其他地方,负责包含所有子表单的父表单已订阅“打开订单”消息,因此它接收消息,并为订单#6打开一个新的子窗口。

由于父母不再直接“焊接”给孩子,现在这些信息也可能来自其他地方。 您可以从父表单本身最近使用的列表中引发“打开订单”消息,或者对单击其他表单中的超链接作出反应。 要求订购#6的不再重要,只有有人这样做。 这是一个高度灵活的模型,消除了很多紧耦合。