MVP Winforms и текстовые поля со списком значений

У меня есть поле со списком в качестве источника данных. Этот список содержит объекты (клиенты) с их свойствами (имя, адрес, ...). Когда я выбираю элемент в выпадающем списке, я хочу передать информацию (адрес, почтовый индекс...) в некоторые текстовые поля в моей форме. В моем тесте 1tier приложения это работает правильно. Но основное приложение, над которым я работаю, основано на MVP (с моим собственным прикосновением к нему). Проблема, с которой я сталкиваюсь - это кастинг. Поскольку мое мнение не знает мою модель, мне нельзя разрешать использовать (Клиенты). string address = ((Customers)comboBox1.SelectedItem).CustomerAddress;

1 Уровень тестирования кода:

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    //getCustomers((int)comboBox1.SelectedValue);
    //txtAddress.Text =Convert.ToString( comboBox1.SelectedValue);
    Customers p = (Customers)comboBox1.SelectedItem;
    string s = comboBox1.SelectedItem.ToString();
    string address = ((Customers)comboBox1.SelectedItem).CustomerAddress;
    txtAddress1.Text = address;
}

private void Form3_Load(object sender, EventArgs e)
{
    using (var emp = new EmployerEFEntities())
    {
        var query = from customers in emp.Customers
                    select customers;

        comboBox1.DisplayMember = "CustomerName";
        comboBox1.ValueMember = "CustomerID";
        comboBox1.DataSource = query.ToList();
    }
}

Я искал это в течение нескольких дней, но не достиг успеха. Я надеюсь, что кто-то может дать мне правильное направление.

Код реального приложения:

Посмотреть:

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    txtName.Text = comboBox1.SelectedValue.ToString();
}

private void CustomerView_Load(object sender, EventArgs e)
{
    comboBox1.DataSource = customerPresenter.getCustomers();
    comboBox1.DisplayMember = "CustomerName";
    comboBox1.ValueMember = "CustomerId";
}

Ведущий:

public List<tbl_customer> getCustomers()
{
    using (var customers = new DBCrownfishEntities())
    {
        var customer = from c in customers.tbl_customer
                       select c;

        return customer.ToList();
    }
}

2 ответа

Решение

Это всего лишь один из способов его реализации. Ваш шаблон MVP может выглядеть иначе. В этой реализации View знает Presenter. Для получения дополнительной информации о MVP вы можете посмотреть здесь

Вы можете использовать Presenter в качестве оболочки для вашего клиента:

public interface IPresenter
{
    void Init();
    void SetSelectedCustomer(int customerId);
    IEnumerable GetCustomers();
    string FirstName { get; set; }
    string LastName { get; set; }
    string Address { get; set; }
}

Презентатор должен реализовать INotifyPropertyChanged (и вызвать OnPropertyChanged в установщиках свойств).

public class Presenter : IPresenter, INotifyPropertyChanged
{
    private readonly Repository _repository;
    private string _firstName;
    private string _lastName;
    private string _address;
    private Customer _currentCustomer;

    public Presenter(Repository repository)
    {
        _repository = repository;
    }

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName == value) return;
            _firstName = value;
            OnPropertyChanged();
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (_lastName == value) return;
            _lastName = value;
            OnPropertyChanged();
        }
    }

    public string Address
    {
        get { return _address; }
        set
        {
            if (_address == value) return;
            _address = value;
            OnPropertyChanged();
        }
    }

    public IEnumerable GetCustomers()
    {
        return _repository.GetAllCustomers();
    }

    public void Init()
    {
        var result = _repository.GetAllCustomers();
        SetSelectedCustomer(result[0].Id);
    }

    public void SetSelectedCustomer(int customerId)
    {
        var customer = _repository.GetCustomerById(customerId);
        FirstName = customer.FirstName;
        LastName = customer.LastName;
        Address = customer.Address;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Вот как выглядит вид:

public partial class Form1 : Form
{
    private IPresenter _presenter;
    private bool _initialized;

    public Form1(IPresenter presenter)
    {
        InitializeComponent();           
        _presenter = presenter;
        _presenter.Init();
        SetComboBoxData(_presenter.GetCustomers());
        _initialized = true;
    }

    public void SetComboBoxData(IEnumerable data)
    {
        comboBox1.DataSource = data;
        comboBox1.ValueMember = "Id";
        comboBox1.DisplayMember = "FirstName";
    }

    private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
    {
        if (!_initialized) return;
        _presenter.SetSelectedCustomer((int)comboBox1.SelectedValue);
    }

    private void Form1_Load(object sender, System.EventArgs e)
    {
        textBox1.DataBindings.Add(new Binding("Text", _presenter, nameof(_presenter.FirstName)));
        textBox2.DataBindings.Add(new Binding("Text", _presenter, nameof(_presenter.LastName)));
        textBox3.DataBindings.Add(new Binding("Text", _presenter, nameof(_presenter.Address)));
    }
}

Вы можете установить выбранный CustomerId в Presenter в своем событии SelectedIndexChanged из вашего выпадающего списка:

_presenter.SetSelectedCustomer((int)comboBox1.SelectedValue);

Метод SetSelectedCustomer в Presenter (или EventHandler для события SelectedCustomerChanged) выбирает Customer с заданным CustomerId и устанавливает FirstName, LastName и Address:

public void SetSelectedCustomer(int customerId)
{
    var customer = _repository.GetCustomerById(customerId);
    FirstName = customer.FirstName;
    LastName = customer.LastName;
    Address = customer.Address;
}

Вы должны сделать привязку для TextBoxes в Form_Load:

textBox1.DataBindings.Add(new Binding("Text", _presenter, nameof(_presenter.FirstName)));
textBox2.DataBindings.Add(new Binding("Text", _presenter, nameof(_presenter.LastName)));
textBox3.DataBindings.Add(new Binding("Text", _presenter, nameof(_presenter.Address)));

Если вы категорически против предоставления вашему представлению доступа к вашим доменным объектам - тем, которые представляют строки таблицы данных (что, в зависимости от того, насколько они тяжелы, в некоторых ситуациях может быть приемлемым)- вы можете захотеть использовать DTO. Проверьте это для хорошего описания соображений и одного подхода к этому. Обратите внимание на упоминание Automapper внизу. Это отличный инструмент.

РЕДАКТИРОВАТЬ: Я только что понял, что вы заинтересованы в решении Winforms, а не для ASP.NET. Хотя приведенная выше ссылка касается ASP.NET, идея аналогична для приложений Winforms.

Другие вопросы по тегам