Что это и для чего надо:
Работа с Datasnap заключается в запросе от сервера данных и вызове серверных методов, например:
- Запросить список товаров с сервера (dataset )
- Создать новый документ
- Добавить в него позиции
- Закрыть документ
Иногда при добавлении позиции необходимо сделать дополнительный выбор, например выбрать партию товара или разрез.
Это можно сделать через возврат кода ошибки (что-то вроде Prepare/Execute), чтобы клиент запросил пользователя, а затем попробовал снова выполнить операцию.
Или же дать серверу возможность запросить клиента непосредственно во время операции все необходимые ему данные.
Первый вариант требует перечня кодов ошибок с соответствующей обработкой.
Второй вариант требует зарегистрировать клиенту функции обратного вызова, которые может вызывать сервер, а также при каждом обращении к серверу иметь в виду, что в ответ сервер может что-то потребовать от клиента (а это грозит блокировкой, если запрос требует реакции от пользователя). Для того, чтобы не было блокировок при однопоточном пользовательском интерфейсе, обращения к серверу нужно делать в отдельном потоке - тогда пришедший от сервера вызов можно синхронизировать с основным потоком (который уже не ждет возврата управления от исходного вызова серверного метода). А также не забывать сообщать серверу ID клиента.
Вызов:
procedure TForm2.btnRegisterWareClick(Sender: TObject);
begin
TThread.CreateAnonymousThread(
procedure()
begin
clmClient.ServerMethods1Client.RegisterWare(seWareID.Value, clmClient.DSClientCallbackChannelManager1.ManagerId)
end).Start;
end;
Сама функция обратного вызова:
TmyCallback = class(TDBXCallback)
protected
FSelectedString: Integer;
procedure SelectString(const Arg: TJSONValue);
public
function Execute(const Arg: TJSONValue): TJSONValue; override;
end;
{ TmyCallback }
function TmyCallback.Execute(const Arg: TJSONValue): TJSONValue;
begin
TThread.Synchronize(nil, procedure() // запрос данных у пользователя - только в основном потоке
begin
SelectString(Arg);
end);
Result := TJSONNumber.Create(FSelectedString);
end;
procedure TmyCallback.SelectString(const Arg: TJSONValue);
var
strs: TStringList;
enum: TJSONPairEnumerator;
val, str: string;
begin
enum := TJSONObject(Arg).GetEnumerator;
if Assigned(enum) then
begin
strs := TStringList.Create;
try
while enum.MoveNext do
begin
Val:= enum.Current.JsonString.Value;
str := enum.Current.JsonValue.Value;
strs.AddObject(str, TObject(val.ToInteger()));
end;
FSelectedString := TfrmSelectString.SelectString(strs);
finally
strs.Free;
end;
end;
enum.Free;
end;
А вот что происходит на сервере:
procedure TServerMethods1.RegisterWare(ID: Integer; ClientID: string);
var
Params, ParamsServ: TJSONObject;
ResObj: TJSONValue;
temp: TJSONValue;
begin
ResObj := nil;
Params := TJSONObject.Create;
Params.AddPair(TJSONPair.Create('1', 'Размер 42'));
Params.AddPair(TJSONPair.Create('2', 'Размер 43'));
Params.AddPair(TJSONPair.Create('3', 'Размер 44'));
ParamsServ := TJSONObject(Params.Clone); //Делаем копию для себя, ибо ушедшую не вернуть
ServerContainer1.DSServer1.NotifyCallback(ClientID, 'SelectString', Params, ResObj);
if Assigned(ResObj) then
begin
temp := ParamsServ.GetValue(ResObj.Value);
if Assigned(temp) then
Form1.QueueLogMsg(Format('RegisterWare %d с разрезом %s', [ID, temp.ToString]))
else
Form1.QueueLogMsg(Format('RegisterWare %d без разреза', [ID]));
ResObj.Free;
ParamsServ.Free;
end
else
Form1.QueueLogMsg(Format('RegisterWare %d без разреза', [ID]));
end;
И напоследок напоминание:
- Локальные переменные процедур - не инициализируются
- Всё, что вы передаете в функцию - можете попрощаться с ними и не освобождать
- Всё, что вы получаете из функции - надо освободить (ведь тут ARC не работает (хотя, надо уточнить для мобилок))
С обратными вызовами можно делать что угодно - передавать в неё готовый набор данных или SQL-запрос, или имя справочника, из которого хранимая процедура вернет набор для выбора.
Код: https://github.com/VladimirSrednikh/datasnap-callback-with-ui
Так как пока с технологией жестко не определился, следующее изучение будет по TRealThinkClient
воскресенье, 17 ноября 2013 г.
воскресенье, 10 ноября 2013 г.
Настроил себе точку доступа на D-Link DWA-125 при помощи утилиты Connectify.
Советы с поднятием SoftAP вручную провалились:
- Динамически адрес подключенному смартфону не выдал => подключения не происходит.
- при указании статического адреса соединение рвется непонятно почему.
P.S. Нет, Connectify тоже не спасение. Время от времени смартфон отключался от свистка и переподключался на домашний роутер с Wi-Fi'ем.
Почему?
P.P.S. Запустил на работе - за 40 минут 20 переподключений. Очень плохо.
Советы с поднятием SoftAP вручную провалились:
- Динамически адрес подключенному смартфону не выдал => подключения не происходит.
- при указании статического адреса соединение рвется непонятно почему.
P.S. Нет, Connectify тоже не спасение. Время от времени смартфон отключался от свистка и переподключался на домашний роутер с Wi-Fi'ем.
Почему?
P.P.S. Запустил на работе - за 40 минут 20 переподключений. Очень плохо.
понедельник, 4 ноября 2013 г.
Пример дизайнера форм FMX
https://drive.google.com/file/d/0B-o0lV3HGn-JcWNUWHhNM3ZYVEk/edit?usp=sharing
Можно кидать на панельку контролы, двигать, изменять размеры.
Есть также дерево объектов, правда пока без редактирования.
Можно кидать на панельку контролы, двигать, изменять размеры.
Есть также дерево объектов, правда пока без редактирования.
суббота, 2 ноября 2013 г.
Oxygene под Андроид
Поставил триалку Оксигена
запустил простое приложение с одной кнопкой
Кнопка выглядит как простой прямоугольник.
запустил простое приложение с одной кнопкой
Кнопка выглядит как простой прямоугольник.
Подписаться на:
Сообщения (Atom)