简体   繁体   中英

C#: DataGridView DataSource Update - DataTable, List, BindingList and BindingSource?

I am still baffled finding out how to get a DataGridView updated automatically when changing the content of its DataSource without explicitely triggering DataGridView.Update() . It seems there is no difference at all between DataTable , List , BindingList as (direct) DataSource and as (indirect) DataSource with an additional BindingSource which uses any of the former as DataSource.

The DataGridView I am actually using for this is non-editable and just shows entries which are updated by the corresponding entity code. My last attempt was with a BindingSource that uses a BindingList and manipulating the content of the BindingSource within the code.

I have omitted some methods here, which do not play a role for the basic problem.

Form:

private void FormLog_Load(object sender, EventArgs e) {
    ...
    dgvLog.DataSource = Log.Current.SourceEntries;
    ...
}

private void ClearLog() {
    Log.Current.RemoveAll();
}

public void UpdateDataSource() {
    dgvLog.Update();
}

Entity (singleton class):

public class LogEntry {
    public int ID { get; set; }
    public string DateTime { get; set; }
    public string Type { get; set; }
    public string Event { get; set; }
    public string Details { get; set; }
}

public class Log {
    public BindingList<LogEntry> Entries { get; set; }
    public BindingSource SourceEntries { get; set; }

public Log() {
    Entries = new BindingList<LogEntry>();
    SourceEntries = new BindingSource() { DataSource = Entries };
    ReadAll();
}

public void Add(string type, string logEvent, string details = "") {
    LogEntry entry = MapToDB(new LogEntry() {
        Type = type,
        Event = logEvent,
        Details = details
    });

    DB.Write(QueryAdd(entry));
    SourceEntries.Add(entry);

    if (Config.Current.GetForm("Log") != null)
        ((FormLog)Config.Current.GetForm("Log")).UpdateDataSource();
}

public void ReadAll() {
    for (int i = SourceEntries.Count - 1; i >= 0; i--) {
        SourceEntries.RemoveAt(i);
    }

    DataTable dt = DB.Read(QueryReadAll());
    if (dt != null) {
        foreach (DataRow row in dt.Rows) {
            SourceEntries.Add(MapToList(row));
        }
    }

    if (Config.Current.GetForm("Log") != null)
        ((FormLog)Config.Current.GetForm("Log")).UpdateDataSource();
}

public void RemoveAll() {
    DB.Write(QueryRemoveAll());

    for (int i = SourceEntries.Count - 1; i >= 0; i--) {
        SourceEntries.RemoveAt(i);
    }

    Add("I", "Log cleared");
}

This works but only when I call UpdateSource() which calls dgvLog.Update() by using a selfwritten FormStack in another singleton class which I would like to avoid. Of course, one could simply call dgvLog.Update() within the form itself but, esp. with this log example, it is obvious that this does not help when updating data from/within another form while the form that displays the DataGridView is still opened in the background.

Also, as there is no difference (between using DataTable or List, etc. and BindingSource or not) I wonder what the benefit/purpose of BindingList and BindingSource are:

Is this the correct approach or am I missing something!?

By the way, I am using .NET v4.5.2.

It seems there is no difference at all between DataTable, List, BindingList as (direct) DataSource and as (indirect) DataSource with an additional BindingSource which uses any of the former as DataSource.

A BindingSource has a few uses

  • maintains knowledge of position/current row and can thus achieve shared navigation (a dgv and textboxes all bound to the same BS means the dgv can navigate through records and the textboxes update because they always show "current row")
  • provides sorting and filtering facilities
  • supports complex binding scenarios where it must help filter a list down to only children of some currently selected parent in a different bindingsource
  • provides separation for multi different positional browsing of a common DataSource

works but only when I call UpdateSource() which calls dgvLog.Update() by using a selfwritten FormStack in another singleton class which I would like to avoid. Of course, one could simply call dgvLog.Update() within the form itself but, esp. with this log example, it is obvious that this does not help when updating data from/within another form while the form that displays the DataGridView is still opened in the background.

Datagridview.Update() is concerned with repainting areas for the control that need it; it is nothing to do with committing changes to underlying data models. Perhaps you need EndEdit which finishes editing operations on the current row and commits them to the underlying data storage. This also happens when you click a different row in a grid. Bindingsource also have an EndEdit method. Mostly you don't need to call these methods yourself

To share data between forms pass the datatable the data is stored in and bind it through a bindingsource in the second form

Also, as there is no difference (between using DataTable or List, etc. and BindingSource or not) I wonder what the benefit/purpose of BindingList and BindingSource are:

DataTable is a collection of DataRow. A DataRow is at it's heart an object array. The end

Binding list is a list of whatever you want, such as your custom class Person. Arguably more useful ultimately, but it's comparing apple's and oranges. If instead you open up the DataSet Designer then you can specify tables that have named typed column. In that regard it's not a huge amount different from writing your own classes (it writes a large amount of good code on a short time though. I use them as data models sometimes

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