Search code examples
c#winformscomboboxmvp

MVP Winforms and textbox combobox values


I have a combobox with a list as datasource. This list contains objects(customers) with their properties (name, address, ...). When i select an item of the combobox, i want to pass the information (address, zipcode...) to some textboxes on my form. In my test 1tier application this works correct. But the main application im working on, is based on MVP (with my own touch on it). The problem that im facing is the casting. As my view does not know my model, i should not be allowed to use the (Customers). string address = ((Customers)comboBox1.SelectedItem).CustomerAddress;

1Tier testing code:

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

I have been looking in to this for a few days now, but haven't come to a success. I hope someone could give me the right direction.

The code of the real application:

View:

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";
}

Presenter:

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

        return customer.ToList();
    }
}

Solution

  • This is just one way to implement it. Your MVP pattern might look different. In this implementation the View knows the Presenter. For more information about MVP you can take a look here

    You can use the Presenter as a Wrapper for your Customer:

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

    The Presenter must implement INotifyPropertyChanged (and call OnPropertyChanged in the Property setters).

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

    This is what the View looks like:

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

    You can set the selected CustomerId at the Presenter in your SelectedIndexChanged event from your combobox:

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

    The SetSelectedCustomer method in your Presenter (or the EventHandler for the SelectedCustomerChanged event) selects the Customer with the given CustomerId and sets the FirstName, LastName and Address:

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

    You should do your Binding for the TextBoxes in 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)));