1

検索してみましたが、探していたものとまったく同じものを見つけることができませんでした。最終的に 4 つまたは 5 つのフォームを持つ WPF デスクトップ アプリケーションを作成しています。各フォームは、電子メールで送信されるデータを収集します。メールを送信するためのコードを含む別のクラス (SendMail) も作成しました。さまざまなフォームのテキスト ボックスからテキストにアクセスし、SendMail クラスのメソッドを介して送信できるようにしたいと考えています。

現在、いくつかのフィールドと次のページ、送信、および終了ボタンを備えた 2 つの基本的なフォームがセットアップされているだけです。次のページに記入する必要がない場合は、どのページからでもデータを送信できるようにしたいと考えています。現在、内部プロパティを介して SendMail クラスから各フォームにアクセスできます。最初のフォームの [送信] ボタンをクリックすると、電子メールが正しく送信されます。ただし、次のフォームに移動して [送信] ボタンをクリックすると、最初のフォームのテキスト ボックスのテキストを参照しているプロパティに対して、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というエラーが表示されます。2 番目のフォームに移動することで、最初のフォームのインスタンスが存在しなくなったと想定しています。

数年前に大学でプログラミングのクラスをいくつか受けましたが、今はもっと真剣に独学で勉強することにしました。私は何冊かの本を読みましたが、数か月しか勉強していないので、おそらく間違った方法でアプローチしています. どんな助けでも大歓迎です。

編集-以下は、要求に応じてコードのサンプルです。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);
    }
}
4

2 に答える 2

0

TextBox最初のフォームの が存在しなくなったことは正しいと思います。そのため、エラーが発生しています。これは、WPF が表示されなくなったコントロールをアンロードし、DataContext内の何かにバインドされていない限り、コントロールからのすべてのデータが忘れられるためです。

WPF を使用している場合は、MVVM デザイン パターンを使用することを強くお勧めします。これはこのテクノロジに完全に適合しており、コードがクリーンで保守しやすい状態に保たれていることがわかりました。

あなたの状況では、私はViewModelあなたのアプリケーション全体に対して1 つを持ちSubmitCommand、それぞれが 1 つの「フォーム」からのデータを表す と 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>

(UserControl を使用する代わりに、DataTemplates の XAML でフォーム コントロールを書き出すこともできます)。

WPF と MVVM デザイン パターンに慣れていない場合は、私のブログに非常に簡単な例があります。

編集

コードで更新された質問を見たところですが、ここでの問題は、SendMailクラスのコピーが 2 つあり、1 つは最初のウィンドウで、もう 1 つは 2 番目のウィンドウであることです。クラスの単一のコピーが必要で、SendMail両方のウィンドウを参照する必要があります。

回答の冒頭で述べたように、WPF は表示されていない UI オブジェクトをアンロードするため、それが機能するとは思わないため、ウィンドウ内のデータが失われる可能性があります.Close()

于 2013-01-16T14:22:34.697 に答える
0

コンストラクターを見てください。

これは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 = 新しい SendMail(これ、親);

しかし、親ウィンドウが閉じられると壊れます。
ただし、親 Windows は MainWindow であるため、とにかくすべてを閉じます。
そのため、失敗する Page1 送信ボタンはもうありません。

于 2013-01-16T15:12:50.463 に答える