Как программно добавить новые строки в таблицу данных winforms в ответ на код триггера, введенный в текущую строку? - PullRequest
0 голосов
/ 25 мая 2011

У меня есть представление данных в приложении c # .net WinForms, которое фиксирует строки детализации заказа. Когда оператор вводит код товара, который является сделкой / составным товаром, я хочу иметь возможность автоматически вставлять части этого товара.

Я подумал, что это будет легко, поскольку у меня есть функция импорта, с помощью которой можно анализировать электронную таблицу и вводить строки непосредственно в таблицу данных. ' s источник данных (строго типизированная таблица). Когда это происходит, сетка хорошо обновляется.

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

Я также пытался использовать BindingSources в качестве источника данных, но это не имеет никакого эффекта.

Я думаю, что это я, потому что код все еще находится в каком-то "событии", и это препятствует добавлению новых строк. Я попытался обработать событие RowEnter, чтобы затем проверить, был ли последний введенный код кодом сделки, но затем я снова оказался в середине события, и все это снова «зависает». Так как же выйти из пузыря событий, чтобы я мог добавлять новые строки?

Часть моего кода ниже:

В подклассе вида сетки данных: (this.Controller.BuildOrderLine (this.CurrentOrderLine);

        protected override void OnCellValueChanged(System.Windows.Forms.DataGridViewCellEventArgs e)
        {
            base.OnCellValueChanged(e);
            if ((this.Order == null) || (this.IsBinding) || (this.SelectedRows.Count == 0) || (e.RowIndex < 0)) { return; }
            this.LockCells(e.RowIndex, !this.IsCurrentOrderLineStubValid);
            this.ComputeOrderLine();
        }  

        protected void ComputeOrderLine()
        {
            if (this.IsReadOnlyGrid) { return; }

                  if (!this.SetCurrentOrderLine(this.CurrentCell.RowIndex)) { return; }
                if (this.CurrentCell.ColumnIndex == COLINDEX_LINEPRICE) { this.CurrentOrderLine.OverrideUnitPriceOn = true; }
                if (this.CurrentCell.ColumnIndex == COLINDEX_DISC)
                {
                    this.CurrentOrderLine.OverrideDiscountOn = true;
                    this.CurrentOrderLine.OverrideDiscountCommitted = false;
                    if (this.IsCurrentCellValueNullOrEmpty) { this.CurrentOrderLine.LineDiscountPct = 0; }
                }

                if (!this.CurrentOrderLine.IsLKeyNull())
                {
                    this.Controller.BuildOrderLine(this.CurrentOrderLine);

                    this.LockCells(this.CurrentRow.Index, this.CurrentOrderLine.IsParentItem);
                    this.HighlightRow(this.CurrentCell.RowIndex);
                }
        }

В контроллере:

public void BuildOrderLine(DBilling.BillingDocumentDetailRow orderLine)
{
    SalesItem item = this.FindMaterialItem(orderLine.LKey);
    orderLine.LineSellingUnit = item.TriggerItem.SellingUnit;
    if (item.IsDealCode)
    {
        this.CurrentOrderLineItem = item;
        this.CurrentOrderLineRow = orderLine;
    }
     this.LineBuilder.ProjectItem(orderLine, item);        }

В объекте бизнес-помощника:

public virtual void ProjectItemDetails(DBilling.BillingDocumentDetailRow headerline, SalesItem item)
{
    if (!item.IsDealCode) { return; }
    DBilling.BillingDocumentDetailRow line = null;

    for (int i = 0; i < item.Parts.Count; i++)
    {
        line = this.DocumentDetail.NewBillingDocumentDetailRow();
        line.MaterialItemId = item.Parts[i].PartItem.PartItemId;
        line.LKey = item.Parts[i].BaseItem.LKey;
        line.MName = item.Parts[i].BaseItem.MName;
        line.ParentItemLineItemId = headerline.LineItemId;
        line.IsParentItem = false;
        line.LineCaptureMethod = "I";
        this.ProjectItemDetailLine(headerline.QuantitySold, ref line, item.Parts[i]);
        this.DocumentDetail.AddBillingDocumentDetailRow(line);
        this.ComputeLineTotals(line);
    }
}

1 Ответ

1 голос
/ 19 июня 2011

Хорошо, поэтому краткий ответ на мою проблему заключался в замене реализаций таблицы данных для BindingSource.В прошлом я сталкивался с несколькими другими проблемами, которые были решены простым использованием компонента BindingSource.В документации действительно говорится, что DataGridView спроектирован так, чтобы работать очень близко с BindingSources, и мой опыт подтверждает это.

Причина, по которой это работает, заключается в том, что DataGridView внутренне использует CurrencyManager для отслеживания положения строки.Хотя я полагал, что этот диспетчер валют обернет источник данных, который я также связал с сеткой, что в некоторой степени и делает, он не зависает и не завершает редактирование текущей строки при использовании источника данных в качестве источника данных.

Так что я предполагаю, что это потому, что таблица не запускает ожидаемые события /, возможно, не реализует соответствующие интерфейсы.

Detail:

Используя Redgate Reflector, я смог углубиться в элемент управления DataGridView.DataGridView использует пару внутренних классов, к которым вы просто не можете получить доступ из своего собственного кода, наиболее важным из которых (для рассматриваемой проблемы) является:

internal class DataGridViewDataConnection

В этом классе есть длинный метод, называемый:

private void ProcessListChanged(ListChangedEventArgs e)

Важной частью этого метода является следующая:

if ((this.owner.NewRowIndex != -1) && (e.NewIndex == this.owner.Rows.Count))
                {
                    throw new InvalidOperationException();
                }
                this.owner.Rows.InsertInternal(e.NewIndex, this.owner.RowTemplateClone, true);
            Label_05B4:
                if (((this.owner.Rows.Count > 0) && !this.dataConnectionState[8]) && !this.owner.InSortOperation)
                {
                    this.MatchCurrencyManagerPosition(false, e.ListChangedType == ListChangedType.Reset);
                }
            }
            finally
            {
                this.dataConnectionState[0x10] = false;
            }

Вы можете видеть, что метод this.MatchCurrencyManagerPosition перемещает текущую позицию строки новой строки в конецсетка, как показано ниже:

public void MatchCurrencyManagerPosition(bool scrollIntoView, bool clearSelection)
{
    if (this.owner.Columns.Count != 0)
    {
        int columnIndex = (this.owner.CurrentCellAddress.X == -1) ? this.owner.FirstDisplayedColumnIndex : this.owner.CurrentCellAddress.X;
        if (columnIndex == -1)
        {
            DataGridViewColumn firstColumn = this.owner.Columns.GetFirstColumn(DataGridViewElementStates.None);
            firstColumn.Visible = true;
            columnIndex = firstColumn.Index;
        }
        int position = this.currencyManager.Position;
        if (position == -1)
        {
            if (!this.owner.SetCurrentCellAddressCore(-1, -1, false, false, false))
            {
                throw new InvalidOperationException(SR.GetString("DataGridView_CellChangeCannotBeCommittedOrAborted"));
            }
        }
        else if (position < this.owner.Rows.Count)
        {
            if ((this.owner.Rows.GetRowState(position) & DataGridViewElementStates.Visible) == DataGridViewElementStates.None)
            {
                this.owner.Rows[position].Visible = true;
            }
            if (((position != this.owner.CurrentCellAddress.Y) || (columnIndex != this.owner.CurrentCellAddress.X)) && ((scrollIntoView && !this.owner.ScrollIntoView(columnIndex, position, true)) || (((columnIndex < this.owner.Columns.Count) && (position < this.owner.Rows.Count)) && !this.owner.SetAndSelectCurrentCellAddress(columnIndex, position, true, false, false, clearSelection, false))))
            {
                throw new InvalidOperationException(SR.GetString("DataGridView_CellChangeCannotBeCommittedOrAborted"));
            }
        }
    }
}

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

Как только я увидел, что внутри DataGridView используется менеджер валют, я решил попробовать замену источника привязки для таблиц данных, что решило проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...