简体   繁体   中英

BindingList, DataGridView and SQL Procedures

I'm trying to build simple data editor.
I've created simple application that uses DataGridView to edit data.
To hold my data objects I'm using BindingList. This way after adding new items my grid is able to show that new entry.
My form is working well, but now I must connect some data to it.
While loading is quite easy I have problem with adding new elements and updating.

I know that I could use SqlDataAdapter and DataTable, but I would like to use BindingList and automatically save all changes using stored procedures.

I've created some model classes:

public class Phone : INotifyPropertyChanged
{
    #region AUTO
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, string propertyName)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    #endregion

    public int PhoneId { get; set; }
    public string Number { get; set; }
    public string Type { get; set; }
    public string TypeTxt { get; set; }

    private bool _valid;
    public bool Valid
    {
        get { return _valid; }
        set { SetField(ref _valid, value, "Valid"); }
    }
}

Right now I only need to catch Valid change so I'm catching only this property change.

public class PhonesList : BindingList<Phone>
{
    public void AddNew(Phone newPhone)
    {
        //here I could call my sql procedure
        Add(newPhone);
    }
}

This class stores my phones, as in comments I could catch add inside AddNew method, but this way I must use AddNew instead of Add

And inside my main form:

    private readonly int _userId;
    private PhonesList _phones;

    private BindingSource _gridSource;

    private BindingSource GridSource
    {
        get { return _gridSource ?? (_gridSource = new BindingSource()); }
    }

    public PhoneDetails(int userId)
    {
        _userId = userId;
        InitializeComponent();
    }

    private void PhoneDetails_Load(object sender, EventArgs e)
    {
        if (_applicationId == 0) return;
        _phones = DB.Instance.LoadPhones(_userId);

        GridSource.DataSource = _phones;
        phonesGV.AutoGenerateColumns = false;
        phonesGV.DataSource = GridSource;
        _phones.ListChanged += _phones_ListChanged;
        _phones.RaiseListChangedEvents = true;
        _phones_ListChanged(null, null);
    }

    void _phones_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
    {
        Text = string.Format("Phones - count: {0}", _phones.Count);
        Refresh();
    }

    private void addNew_Click(object sender, EventArgs e)
    {
        errorProvider1.Clear();
        if(newPhoneNumberTb.Text.Length<9)
        {
            errorProvider1.SetError(newPhoneNumberTb,"9 digits minimum!");
            return;
        }
        if (newPhoneTypeCb.SelectedItem==null)
        {
            errorProvider1.SetError(newPhoneTypeCb, "Choose phone type!");
            return;
        }
        _phones.AddNew(new Phone
            {
                Number = newPhoneNumberTb.Text.Trim(),
                PhoneId = 0,
                Type = newPhoneTypeCb.SelectedItem.ToString(),
                TypeTxt = newPhoneTypeCb.SelectedItem.ToString(),
                Valid = true
            });
        newPhoneNumberTb.Text = "";
        newPhoneTypeCb.SelectedItem = null;
    }

I'm able to load data into my form using stored procedure, but right now I would like to call stored procedure that add new phone and update it when necessary.

Where should I listen for add/update "events"?
Is it correct to add add/update functionality to models?

Ideally I could add add/update to Phone Model, but this way I'll have problem with loading data, because every time I'll create instance my 'Add' query will be called.

Here is my LoadPhones:

    public PhonesList LoadPhones(int userId)
    {
        var phones = new PhonesList();

        using (var conn = new SqlConnection(ConnStr))
        {
            using (var cmd = new SqlCommand(@"LoadTelefonow", conn))
            {
                cmd.Parameters.Add("@USER_ID", SqlDbType.Int).Value = userId;
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandTimeout = 360;
                conn.Open();
                using (SqlDataReader sdr = cmd.ExecuteReader())
                {
                    while (sdr.Read())
                    {
                        var phone = new Phone
                        {
                            PhoneId = Convert.ToInt32(sdr["Tel_Id"]),
                            Number = Convert.ToString(sdr["Number"]),
                            Type = Convert.ToString(sdr["Typ"]),
                            TypeTxt = Convert.ToString(sdr["Typ"]),
                            Valid = Convert.ToBoolean(sdr["Status"])
                        };
                        phones.Add(phone);
                    }
                }
                conn.Close();
            }
        }
        return phones;
    }

So my question is: Where and how should I add adding and updating functionality to my BindingList of my Phone model (don't know which one would be better)?

To Update:

Using BindingSource as the DataGridView 's DataSource is good to be notified when a property changes inorder to update the corresponding item. You can do something like this:

In your MainForm or through designer:

datagridview1.DataSource = bindingSource1;
bindingSource1.CurrentItemChanged += new EventHandler(bindingSource1_CurrentItemChanged);

Declate a field in your form to maintain a list of changed items:

private List<int> UpdatedItemsIndex;

And add to it when something changes:

private void bindingSource1_CurrentItemChanged(object sender, EventArgs e)
{
    UpdatedItemsIndex.Add(bindingSource1.IndexOf(bindingSource1.Current));
}

To Add: Likewise, use BindingSource and handles AddNew

bindingSource1.AddingNew += new System.ComponentModel.AddingNewEventHandler(this.bindingSource1_AddingNew);

And:

List<int> AddedItemsIndex = new List<int>();
private void bindingSource1_AddingNew(object sender, AddingNewEventArgs e)
{
    AddedItemsIndex .Add(bindingSource1.Count);
}

To Save Changes : Add/Update based on the lists. Remeber to clear them after they are inserted/updated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM