【问题标题】:I need to access a form control from another class (C#)我需要从另一个类(C#)访问表单控件
【发布时间】:2014-12-26 13:54:19
【问题描述】:

在我的表单上,我有一个名为“panelShowList”的 Panel 容器。

在我的项目中,我添加了一个新类,如下所示:

class myNewClass
{
    private int newPanelPos = 30;
    private const int spaceBetweenElements = 30;
    private const int panelWidth = 90;
    private const int panelHeight = 40;
    private int elementPos = 0;

    private ArrayList myPanels = new ArrayList() { };

    // some irelevant methods

    public void addElementPanels(Panel dataPanel, Panel nextPanel)
    {
        myPanels.Add(dataPanel);
        myPanels.Add(nextPanel);
    }

    public void displayPanels()
    {
        foreach (Panel tmp in myPanels)
        {
            // here i'm stuck

            // i need to do something like this :
            // myMainForm.panelShowList.Controls.Add(tmp);
            // of course this is wrong! but i need a method to acces that control
        }
    }
}

基本上,我需要一种方法将 ArrayList 中的所有面板添加到表单中的“panelShowList”控件上。

我尝试过这样的事情:

public void displayPanels()
    {
        frmMain f = new frmMain();
        foreach (Panel tmp in myPanels)
        {

            f.display(tmp);
            // where display(Panel tmp) is a function in my Form, who access
            // "panelShowList" control and add a new Panel
        }
    }

但只有当我这样做时它才有效:

f.ShowDialog();

另一个表格打开了。

任何建议将不胜感激。

【问题讨论】:

  • 表单只有在打开时才存在。所以不开放的时候不访问是正常的。要修复它,您需要创建一个静态对象并将表单存储在其中。所以你可以在它关闭时访问它。
  • @vgSefa:本质上是使用静态值作为全局变量,这是一种非常糟糕的使用模式。保持值的范围比将它们转储到某个地方让所有人看到要好。此外,您的第一个陈述(“表单仅在打开时才存在”)显然是错误的。与任何对象一样,表单对象只要在范围内就存在。
  • 请不要使用ArrayList。在这种情况下最好使用通用列表:private IList<Panel> myPanels = new List<Panel>();
  • @khlr 非常感谢您的建议。我对 C# 没有任何经验,所以我还在学习很多东西。

标签: c#


【解决方案1】:

可能有点晚了,但无论如何,这是另一种方法,它仍然比大卫的方法更干净:

您应该在 MyNewClass 中添加一个 EventHandler。然后,您可以在表单中订阅该事件。

public partial class Form1 : Form
{
    private readonly MyNewClass _myNewClass;

    public Form1()
    {
        InitializeComponent();
        _myNewClass = new MyNewClass();
        _myNewClass.DisplayPanelsInvoked += DisplayPanelsInvoked;
    }

    private void DisplayPanelsInvoked(object sender, DisplayPanelsEventArgs e)
    {
        var panels = e.Panels; // Add the panels somewhere on the UI ;)
    }
}

internal class MyNewClass
{
    private IList<Panel> _panels = new List<Panel>();

    public void AddPanel(Panel panel)
    {
        _panels.Add(panel);
    }

    public void DisplayPanels()
    {
        OnDisplayPanels(new DisplayPanelsEventArgs(_panels));
    }

    protected virtual void OnDisplayPanels(DisplayPanelsEventArgs e)
    {
        EventHandler<DisplayPanelsEventArgs> handler = DisplayPanelsInvoked;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    public event EventHandler<DisplayPanelsEventArgs> DisplayPanelsInvoked;
}

internal class DisplayPanelsEventArgs : EventArgs
{
    public DisplayPanelsEventArgs(IList<Panel> panels)
    {
        Panels = panels;
    }

    public IList<Panel> Panels { get; private set; }
}

在我看来,这是一个更好的解决方案,因为您不需要提供对 MyNewClass 实例的表单引用。所以这种方法减少了耦合,因为只有表单对 MyNewClass 有依赖。

如果您总是想在添加面板时“更新”表单,您可以删除DisplayPanels-方法并将代码缩短为:

public partial class Form1 : Form
{
    private readonly MyNewClass _myNewClass;

    public Form1()
    {
        InitializeComponent();
        _myNewClass = new MyNewClass();
        _myNewClass.PanelAdded += PanelAdded;
    }

    private void PanelAdded(object sender, DisplayPanelsEventArgs e)
    {
        var panels = e.AllPanels; // Add the panels somewhere on the UI ;)
    }
}

internal class MyNewClass
{
    private IList<Panel> _panels = new List<Panel>();

    public void AddPanel(Panel panel)
    {
        _panels.Add(panel);
        OnPanelAdded(new DisplayPanelsEventArgs(_panels, panel)); // raise event, everytime a panel is added
    }

    protected virtual void OnPanelAdded(DisplayPanelsEventArgs e)
    {
        EventHandler<DisplayPanelsEventArgs> handler = PanelAdded;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    public event EventHandler<DisplayPanelsEventArgs> PanelAdded;
}

internal class DisplayPanelsEventArgs : EventArgs
{
    public DisplayPanelsEventArgs(IList<Panel> allPanels, Panel panelAddedLast)
    {
        AllPanels = allPanels;
        PanelAddedLast = panelAddedLast;
    }

    public IList<Panel> AllPanels { get; private set; }
    public Panel PanelAddedLast { get; private set; }
}

【讨论】:

    【解决方案2】:

    另一个表格打开了

    那是因为您正在创建一个全新的表单:

    frmMain f = new frmMain();
    

    如果您想修改现有表单的状态,该代码将需要对该表单的引用。有很多方法可以做到这一点。一种可能是简单地传递对该方法的引用:

    public void displayPanels(frmMain myMainForm)
    {
        foreach (Panel tmp in myPanels)
        {
            // myMainForm.panelShowList.Controls.Add(tmp);
            // etc.
        }
    }
    

    然后,当您的主窗体调用该方法时,它会提供对自身的引用:

    instanceOfNewClass.displayPanels(this);
    

    不过,说实话,目前还不清楚您要在这里采用哪种结构。如果代码正在修改表单,那么我想代码应该在该表单上。它当然可以组织成一个类,但也许它可以是那种形式的内部类,因为没有其他东西需要知道它。

    我还担心您的myNewClass 实现需要以特定顺序调用方法。对对象的任何给定操作都应完全封装完成该操作的逻辑。如果对象在该逻辑完成之前不处于有效状态,则其中一些初始化逻辑可能属于构造函数。

    不过,这有点猜想,因为这里的对象结构并不清楚。

    【讨论】:

      猜你喜欢
      • 2019-09-23
      • 2016-05-06
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 1970-01-01
      • 2012-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多