【问题标题】:Accessing data from multiple forms in C#在 C# 中从多个表单访问数据
【发布时间】:2013-01-16 14:09:19
【问题描述】:

我尝试搜索,但找不到任何能完全满足我的需求的东西。我正在创建一个 WPF 桌面应用程序,它最终将有四个或五个表单。每个表格都将收集要通过电子邮件发送的数据。我还创建了一个单独的类 (SendMail),其中包含发送电子邮件的代码。我希望能够从各种表单的文本框中访问文本并通过 SendMail 类中的方法发送它们。

目前,我只设置了两个基本表单,其中包含几个字段和下一页、提交和退出按钮。如果以下页面都不需要填写,我希望能够从任何页面提交数据。我目前能够通过内部属性从 SendMail 类访问每个表单,当我点击第一个表单上的提交按钮时,电子邮件会正确发送。但是,如果我转到下一个表单并单击“提交”按钮,我会收到“对象引用未设置为对象的实例”错误,因为该属性引用了第一个表单上的文本框的文本。我假设通过转到第二种形式,第一种形式的实例不再存在。

几年前我在大学里参加了一些编程课程,但现在我决定自己更认真地学习它。我读过几本书,但只学习了几个月,所以我可能以错误的方式接近这一点。任何帮助表示赞赏。

编辑- 根据要求,以下是一些代码示例。我从 SendMail 类中删除了电子邮件地址/密码。

第一个窗口

public partial class MainWindow : Window
{
    SendMail page1;

    // Properties to allow access to SendMail.
    internal string CmbEmail
    {
        get { return this.cmbEmail.Text; }
    }

    internal string DateWritten
    {
        get { return this.dateWritten.Text; }
    }

    public MainWindow()
    {
        InitializeComponent();
        page1 = new SendMail(this);
    }

    private void btnSubmit_Click_1(object sender, RoutedEventArgs e)
    {
        page1.Email();
    }

    private void btnNextPage_Click(object sender, RoutedEventArgs e)
    {
        Window1 nextPage = new Window1(this);
        nextPage.Show();
        this.Close();
    }
}

第二个窗口

public partial class Window1 : Window
{
    SendMail page2;

    public Window1(MainWindow parent)
    {
        InitializeComponent();
        page2 = new SendMail(this);
    }

    private void btnExit_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }

    private void btnSubmit_Click(object sender, RoutedEventArgs e)
    {
        page2.Email();
    }
}

发送邮件类

class SendMail
{
    MainWindow page1;
    Window1 page2;

    public SendMail(MainWindow form)
    {
        page1 = form;
    }

    public SendMail(Window1 form)
    {
        page2 = form;
    }

    public void Email()
    {
        NetworkCredential cred = new NetworkCredential("", "");
        MailMessage msg = new MailMessage();
        msg.To.Add("");

        // Send an email to address in the Email field, if not empty.
        if (page1.CmbEmail != "") // This is the line throwing the error, but only when submitting from the second window.
        {
            msg.To.Add(page1.CmbEmail);
        }

        msg.From = new MailAddress("");
        msg.Subject = "Garment Order " + page1.DateWritten.ToString();
        msg.Body = "Test email";

        SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
        client.Credentials = cred;
        client.EnableSsl = true;
        client.Send(msg);
    }
}

【问题讨论】:

  • WPF 没有表单。发布错误的行的代码。
  • 向我们展示您的尝试
  • 对不起,窗口,不是窗体。我将编辑我的原始帖子并添加一些代码。

标签: c# wpf multiple-forms


【解决方案1】:

我认为您是正确的,第一个表单上的 TextBox 不再存在,这就是您收到错误的原因。这是因为 WPF 会卸载不再可见的控件,并且它们中的所有数据都会被遗忘,除非它们绑定到 DataContext 中的某些内容。

如果您正在使用 WPF,我强烈建议您使用 MVVM 设计模式。它非常适合这项技术,而且我发现它使代码保持干净且易于维护。

在您的情况下,我将为您的整个应用程序创建一个 ViewModel,并让它包含 SubmitCommand 和 5 个数据对象,每个对象代表一个“表单”中的数据

例如,您的 MainViewModel 可能如下所示:

public MainViewModel : INotifyPropertyChanged
{
    // Should be full properties that implement INotifyPropertyChanged, 
    // but leaving that out for simplicity right now
    public ObservableCollection<object> Forms { get; set; }
    public object CurrentForm { get; set; }

    public ICommand SubmitCommand { get; set; }
    // Could also add ICommands for Back and Next buttons as well

    public MainViewModel()
    {
        Forms = new ObservableCollection()
        {
            new Form1Data(),
            new Form2Data(),
            new Form3Data(),
            new Form4Data(),
            new Form5Data()
        };

        CurrentForm = Forms.FirstOrDefault();
    }
}

你的 XAML 看起来像这样:

<Window>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Form1Data}">
            <local:Form1UserControl /> 
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:Form2Data}">
            <local:Form2UserControl /> 
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:Form3Data}">
            <local:Form3UserControl /> 
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:Form4Data}">
            <local:Form4UserControl /> 
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:Form5Data}">
            <local:Form5UserControl /> 
        </DataTemplate>
    </Window.Resources>

    <DockPanel>
        <Button Command="{Binding SubmitCommand}" 
                Content="Submit" DockPanel.Dock="Bottom" />

        <ContentControl Content="{Binding CurrentForm}" />
    </DockPanel>
</Window>

(您也可以在 DataTemplates 中用 XAML 编写表单控件,而不是使用 UserControl)

如果您是 WPF 和 MVVM 设计模式的新手,我有一个非常好的simple example on my blog,您可能有兴趣阅读以开始使用。

编辑

我刚刚看到您的代码更新问题,您的问题是您有两个 SendMail 类副本,一个带有您的第一个窗口,一个带有您的第二个窗口。您需要拥有SendMail 类的一个副本,并让它引用两个窗口。

虽然就像我在回答开头所说的那样,但我认为这不会起作用,因为 WPF 会卸载不可见的 UI 对象,因此当您 .Close() 时,您的 Window 中的任何数据都可能会丢失它。

【讨论】:

  • 感谢您的广泛回答和洞察力。我对 WPF 很陌生,只对 MVVM 进行了少量研究。当我有更多时间时,我会看看你的博客。看起来它有一些很棒的信息。
  • 我不知道为什么我没有想到这一点。我进行了必要的更改,现在我可以从两个窗口提交。再次感谢您的帮助。我仍将查看您的博客并更广泛地研究 MVVM,因为我想学习有效地编码,但这将适用于我试图通过此应用程序完成的工作。
【解决方案2】:

查看构造函数。

这将使用第二个 ctor(而不是分配 page1)

page2 = new SendMail(this);

上面这是一个Window1

public SendMail(MainWindow form)
{
    page1 = form;
}

public SendMail(Window1 form)
{
    page2 = form;
}

Window1 ctor 没有分配 page1。
所以 page1.CmbEmail 将抛出“对象引用未设置为对象的实例”。

我认为你可以解决这个问题

   public SendMail(Window1 form, MainWindow mainWindow)
    {
        page2 = form;
        page1 = mainWindow;
    }

然后当你调用它时

page2 = new SendMail(this, parent);

但是,如果父窗口关闭,就会中断。
但由于父窗口是 MainWindow 无论如何都会关闭所有内容。
所以不会再有一个 Page1 提交按钮会失败。

【讨论】:

  • 有道理。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2016-04-10
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多