Как отменить все изменения в источнике привязки?

У меня есть две кнопки - отменить и добавить, которые добавляют новую строку в виде сетки, и соответственно каждый раз, когда я нажимаю ее, в контекст добавляется новая запись, которая подключена к источнику привязки, который установлен как источник данных вид сетки.

Поэтому, если у меня есть 2 строки и я добавляю 8 строк (например), когда я нажимаю «Отмена», он должен очищать только несохраненные строки и снова оставлять их двумя.

Проблема в том, что он отменяет только 4 из них (я вижу проблему в своем коде, но не могу найти способ ее исправить).

Вот мой простой код, который пока не работает:

try
        {
            DialogResult dialogResult = MessageBox.Show("Do you want to cancel all unsaved changes?", "Cancel all unsaved changes", MessageBoxButtons.YesNo);
            if (dialogResult == DialogResult.Yes)
            {
                for (var i = 0; i < bindingSource1.Count; i++)
                {
                    var f = bindingSource1[i] as MyConfiguration;

                    if (f.MyConfigurationId == 0)
                    {
                        context.RemoveMyConfiguration(f);
                        bindingSource1.Remove(f);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }

Проблема в том, что я перебираю источник привязки и одновременно удаляю элементы, и он обновляется, поэтому в какой-то момент он может увидеть, что он зациклился на всей коллекции.

Каков правильный путь? Должен ли я перебирать строки в сетке?

РЕДАКТИРОВАТЬ: я извиняюсь за это, это WinForms. Источником данных BindingSource является список, полученный из базы данных. Я использую Entity Framework 4.0.


person Apostrofix    schedule 06.11.2014    source источник
comment
Когда вы говорите представление сетки, вы имеете в виду ASP.NET GridView или на самом деле WinForms DataGridView? Каков источник данных для BindingSource?   -  person jmcilhinney    schedule 06.11.2014
comment
Прошу прощения за это, это WinForms. Источником данных BindingSource является List‹MyConfiguration›, полученный из базы данных. Я использую Entity Framework 4.0.   -  person Apostrofix    schedule 06.11.2014
comment
@jmcilhinney На самом деле я использую представление сетки DevExpress, но я думаю, что это тот же принцип, что и DataGridView   -  person Apostrofix    schedule 06.11.2014


Ответы (2)


Ваша проблема заключается просто в том, что вы удаляете элементы из списка, который перебираете. Если вы удаляете элемент из списка BindingSources, элементы перед ним перемещаются на один индекс назад, что означает, что вы пропустите элемент, который был перемещен в индекс, из которого вы удалили элемент.

Самое простое решение — переместить приращение счетчика в блок else, чтобы счетчик увеличивался только в том случае, если элемент НЕ удален, в противном случае вы хотите снова проверить тот же индекс, как новый элемент теперь занимает этот индекс.

Дополнительная информация: я бы рекомендовал взглянуть на BindingList и рассмотрите возможность использования его в качестве источника данных для BindingSource вместо обычного List<T>. Основное преимущество использования списка привязок в сочетании с источником привязки заключается в том, что список привязок запускает события при изменении списка, эти события подписываются источником привязки. Это означает, что вам нужно «беспокоиться» только о внесении изменений в ваш экземпляр BindingList — изменения подхватываются источником привязки и отражаются в элементах управления, использующих источник привязки в качестве источника данных.

Супер-мега-джекпот-информация: если вы хотите отменить изменения, внесенные в один элемент в BindingSource (находится в свойстве Current), вы можете использовать метод CancelEdit. Но чтобы это имело какой-либо эффект, тип объекта, содержащийся в источнике привязки, должен реализовать интерфейс IEditableObject

person TDull    schedule 08.11.2014

Как насчет LINQ? Я не знаю, что такое тип bindingSource1, но я предполагаю, что это коллекция, которая реализует IEnumerable, поэтому методы расширения LINQ будут доступны.

try
        {
            DialogResult dialogResult = MessageBox.Show("Do you want to cancel all unsaved changes?", "Cancel all unsaved changes", MessageBoxButtons.YesNo);
            if (dialogResult == DialogResult.Yes)
            {
                bindingSource1 = bindingSource1.Where(bs => (bs as MyConfiguration).MyConfigurationId != 0);//.ToList(); if needed
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }

Я не знаю, что такое context, но с помощью этого метода вы не можете его обновить, но вы можете найти обходной путь, смешав свой способ с предыдущей операцией. Вы можете перебирать временную коллекцию вместо того, чтобы перебирать bindingSource1 напрямую, примерно так:

try
        {
            DialogResult dialogResult = MessageBox.Show("Do you want to cancel all unsaved changes?", "Cancel all unsaved changes", MessageBoxButtons.YesNo);
            if (dialogResult == DialogResult.Yes)
            {
                foreach (MyConfiguration f in bindingSource1.Select(bs => bs as MyConfiguration).Where(bs => bs.MyConfigurationId == 0))
                {
                        context.RemoveMyConfiguration(f);
                        bindingSource1.Remove(f);
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }

В приведенном выше примере мы перебираем только временную коллекцию с несохраненными элементами и удаляем каждый из них из context и bindingSource1.

person frikinside    schedule 06.11.2014