Доступ к данным из нескольких форм в C#

Я пытался искать, но не смог найти ничего, что дало бы мне именно то, что я искал. Я создаю настольное приложение 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);
    }
}

person jlbridenstine    schedule 16.01.2013    source источник
comment
WPF не имеет формы. Почтовый код строки, которая выдает ошибку.   -  person paparazzo    schedule 16.01.2013
comment
покажи нам, что ты пробовал   -  person Prahalad Gaggar    schedule 16.01.2013
comment
Извините, окна, а не формы. Я отредактирую свой исходный пост и добавлю немного кода.   -  person jlbridenstine    schedule 16.01.2013


Ответы (2)


Я думаю, вы правы, что TextBox в первой форме больше не существует, поэтому вы получаете сообщение об ошибке. Это связано с тем, что WPF выгружает элементы управления, которые больше не видны, и все данные из них забываются, если только они не привязаны к чему-либо в DataContext.

Я настоятельно рекомендую использовать шаблон проектирования MVVM, если вы работаете с WPF. Он идеально подходит для этой технологии, и я считаю, что код остается чистым и простым в обслуживании.

В вашей ситуации у меня был бы один 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>

(Вы также можете написать элементы управления формы в XAML в DataTemplates вместо использования UserControl)

Если вы новичок в WPF и шаблоне проектирования MVVM, у меня есть очень простой пример на мой блог, который вам может быть интересно прочитать для начала.

Изменить

Я только что видел ваш обновленный вопрос с кодом, и ваша проблема здесь в том, что у вас есть две копии вашего класса SendMail, одна с вашим первым окном и одна со вторым окном. Вам нужна единственная копия класса SendMail, и она должна ссылаться на оба окна.

Хотя, как я сказал в начале своего ответа, я не думаю, что это сработает, потому что WPF выгружает невидимые объекты пользовательского интерфейса, поэтому вполне вероятно, что любые данные в вашем окне будут потеряны, когда вы .Close() его.

person Rachel    schedule 16.01.2013
comment
Спасибо за развернутый ответ и понимание. Я новичок в WPF и провел лишь небольшое исследование MVVM. Я проверю ваш блог, когда у меня будет немного больше времени. Похоже, у него есть отличная информация. - person jlbridenstine; 16.01.2013
comment
Не знаю, почему я не подумал об этом. Я внес необходимые изменения, и теперь я могу отправлять сообщения из обоих окон. Спасибо еще раз за помощь. Я все еще собираюсь проверить ваш блог и более подробно изучить MVVM, так как я хочу научиться эффективно кодировать, но это будет работать для того, чего я пытаюсь достичь с помощью этого приложения. - person jlbridenstine; 16.01.2013

Посмотрите на конструкторов.

Это будет использовать 2-й ctor (и не назначать page1)

page2 = new SendMail(this);

Выше это Window1

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

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

Ctor Window1 не назначает page1.
Таким образом, page1.CmbEmail выдаст сообщение "Ссылка на объект не указывает на экземпляр объекта".

Я думаю, вы могли бы исправить это с помощью

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

Затем, когда вы называете это

page2 = новый SendMail(это, родитель);

Но это ломается, если родительское окно закрывается.
Но поскольку родительское окно является основным окном, оно в любом случае закроет все.
Таким образом, больше не будет кнопки отправки Page1, которая не сработает.

person paparazzo    schedule 16.01.2013
comment
Имеет смысл. Спасибо за помощь. - person jlbridenstine; 16.01.2013