1

我尝试搜索,但找不到任何能完全满足我的需求的东西。我正在创建一个 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);
    }
}
4

2 回答 2

0

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

I would highly recommend using the MVVM design pattern if you're working with WPF. It's perfectly suited to the technology, and I find it keeps the code clean and easy to maintain.

In your situation, I would have a single ViewModel for your entire application, and have it contain the SubmitCommand and 5 data objects, each representing the data from one "Form"

For example, your MainViewModel might look like this:

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();
    }
}

And your XAML would look something like this:

<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>

(You could also write out form controls in XAML in the DataTemplates instead of using a UserControl)

If you're new to WPF and the MVVM design pattern, I have a very simple example on my blog that you may be interested in reading to get started.

Edit

I just saw your updated question with the code, and your problem here is that you have two copies of your SendMail class, one with your first window and one with your second window. You need to have a single copy of the SendMail class, and have it reference both windows.

Although like I said in the beginning of my answer, I don't think that will work because WPF unloads UI objects that aren't visible, so it's likely that any data in your Window will be lost when you .Close() it.

于 2013-01-16T14:22:34.697 回答
0

Look at the constructors.

This will use the 2nd ctor (and not assign page1)

page2 = new SendMail(this);

The above this is a Window1

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

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

The Window1 ctor does not assign page1.
So page1.CmbEmail is going to throw a "Object reference not set to an instance of an object".

I think you could fix this with

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

Then when you call it

page2 = new SendMail(this, parent);

But that breaks if the parent Window gets closed.
But since the parent Windows is the MainWindow that would close everything anyway.
So there would not longer be a Page1 submitt button that would fail.

于 2013-01-16T15:12:50.463 回答