powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Странности с TDBLookupComboBox
6 сообщений из 6, страница 1 из 1
Странности с TDBLookupComboBox
    #39527933
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть TDBLookupComboBox с установленными ListSource, ListField. Делаю так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
procedure TForm1.btnTestClick(Sender: TObject);
var
  LDS: TDataSet;
begin
  LDS := DBLookupComboBox1.ListSource.DataSet;
  LDS.DisableControls;
  try
    LDS.Close;
    LDS.Open;
  finally
    LDS.EnableControls;
  end;
end;

после этого работа комбобокса - это черный ящик.

Что происходит: внутри комбобокса (а вернее его родителя TDBLookupControl) есть поле
Код: pascal
1.
FListField: TField;

оно заполняется в методе TDBLookupControl.UpdateListFields на основании поля
Код: pascal
1.
FListFieldName: string;

Этот метод вызывается из TDataLink на событие датасета
Код: pascal
1.
DataSet.DataEvent(deUpdateState, 0);


А теперь проблема - при закрытии датасета для всех полей вызывается
Код: pascal
1.
TField.Free

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

Собственно вопрос - как бы минимальными телодвижениями заставить комбобокс переинициализировать свой FListField?

Обнаружено на XE3


С уважением, Vasilisk
...
Рейтинг: 0 / 0
Странности с TDBLookupComboBox
    #39528536
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Валится вот с таким кодом
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
procedure TForm1.btnTestClick(Sender: TObject);
var
  LDS: TDataSet;
  LList: TObjectList<TField>;
  Li: Integer;
begin
  LList := TObjectList<TField>.Create(True);
  try
    LDS := DBLookupComboBox1.ListSource.DataSet;
    LDS.DisableControls;
    try
      LDS.Close;
      for Li := 0 to 9 do
        LList.Add(TIntegerField.Create(nil));
      LDS.Open;
    finally
      LDS.EnableControls;
    end;
  finally
    LList.Free;
  end;
end;
...
Рейтинг: 0 / 0
Странности с TDBLookupComboBox
    #39528581
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем вскрытие показало:

D2007
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
procedure TDataSet.DataEvent(Event: TDataEvent; Info: NativeInt);
begin
  NotifyDataSources := not (ControlsDisabled or (State = dsBlockRead));
  case Event of
    .............
    deUpdateState:
      if ControlsDisabled then
      begin
        Event := deDisabledStateChange;
        Info := Integer(State <> dsInactive);
        NotifyDataSources := True;
        FEnableEvent := deLayoutChange;
      end;
    ...............
end;


Delphi XE3
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
procedure TDataSet.DataEvent(Event: TDataEvent; Info: NativeInt);
begin
  NotifyDataSources := not (ControlsDisabled or (State = dsBlockRead));
  case Event of
    .............
    deUpdateState:
      // Send a special event to allow field references to be cleared by data aware controls
      // if a dataset is closed or opened while controls are disabled.
      if ControlsDisabled then
      begin
        IsActive := State <> dsInactive;
        if (IsActive and (FEnableEvent = deLayoutChange)) or         // Opening or
           (not IsActive and (FEnableEvent = deDataSetChange)) then  // Closing
        begin
          Event := deDisabledStateChange;
          NotifyDataSources := True;
          Info := IntPtr(IsActive);
          if IsActive then
            FEnableEvent := deDataSetChange
          else
            FEnableEvent := deLayoutChange;
        end;
      end;
    ...............
end;


Delphi XE7
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
procedure TDataSet.DataEvent(Event: TDataEvent; Info: NativeInt);
begin
  NotifyDataSources := not (ControlsDisabled or (State = dsBlockRead));
  case Event of
    .............
    deUpdateState:
      // Send a special event to allow field references to be cleared by data aware controls
      // if a dataset is closed or opened while controls are disabled.
      if ControlsDisabled then
      begin
        IsActive := State <> dsInactive;
        if (IsActive and (FEnableEvent = deLayoutChange)) or         // Opening or
           (not IsActive and (FEnableEvent = deDataSetChange)) then  // Closing
        begin
          Event := deDisabledStateChange;
          NotifyDataSources := True;
          Info := IntPtr(IsActive);
          if IsActive and (FEnableEvent <> deLayoutChange) then
            FEnableEvent := deDataSetChange
          else
            FEnableEvent := deLayoutChange;
        end;
      end;
    ...............
end;


Т.е. при вызове EnabledControls во всех версиях проходит событие deLayoutChange, которое DataLink правильно обрабатывает
Код: pascal
1.
2.
3.
4.
procedure TListSourceLink.LayoutChanged;
begin
  if FDBLookupControl <> nil then FDBLookupControl.UpdateListFields;
end;

А в ХЕ3 оно затирается событием deDataSetChange, которое обрабатывается так
Код: pascal
1.
2.
3.
4.
procedure TListSourceLink.DataSetChanged;
begin
  if FDBLookupControl <> nil then FDBLookupControl.ListLinkDataChanged;
end;



Решение-костыль
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
type
  {$IFDEF VER240}  // DelphiXE3
  TDBLookupComboBox = class(Vcl.DBCtrls.TDBLookupComboBox)
  protected
    procedure ListLinkDataChanged; override;
  end;
  {$ENDIF}

{ TDBLookupComboBox }

{$IFDEF VER240}
procedure TDBLookupComboBox.ListLinkDataChanged;
begin
  UpdateListFields;
  inherited ListLinkDataChanged;
end;
{$ENDIF}
...
Рейтинг: 0 / 0
Странности с TDBLookupComboBox
    #39528586
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_Решение-костыльНедопроверил. Такой костыль вызывает Stack Overflow. Не хочется переопределять TDataSet.DataEvent. Используется куча разных датасетов
...
Рейтинг: 0 / 0
Странности с TDBLookupComboBox
    #39528597
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здесь RSP-19036 люди жалуются на Берлин. А ноги растут оттуда же
...
Рейтинг: 0 / 0
Странности с TDBLookupComboBox
    #39528606
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В итоге скопировал модуль Data.DB в отдельную папку, поменял строчку
Код: pascal
1.
if IsActive then

на
Код: pascal
1.
if IsActive and (FEnableEvent <> deLayoutChange) then

и добавил эту папку в Library Path
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Странности с TDBLookupComboBox
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]