我试着搜索,但找不到任何能让我满意的东西。我正在创建一个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();
}
}
SendMail类
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);
}
}
答案 0 :(得分:0)
我认为你的第一个表单上的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对象,所以当{{1}时,窗口中的任何数据都可能会丢失它。
答案 1 :(得分:0)
看看构造函数。
这将使用第二个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);
但如果父窗口关闭,则会中断 但是,由于父Windows是MainWindow,无论如何都会关闭所有内容 所以不会有一个失败的Page1提交按钮。