Buenas tardes, amigos!

Господа, прошу руку помощи в следующем, непонятном мне моменте.

Существует окно, в нём есть список и memo поле.
При инициализации окна, полю memo устанавливается свойство IsReadOnly = true;
При изменении пункта в списке (на какой то определённый) устанавливается свойство memo.IsReadOnly = false, но само поле в окне остаётся недоступным.

Где здесь собака зарыта?

С уважением
Ваш коллега.

Нравится

13 комментариев

Yegor, проверьте чему установлено свойство IsEnabled (посмотрите как визуально в свойствах элемента, так и не устанавливается ли свойство программно).
Чтобы понять в чем причина поможет реализованный Вами код либо сервисы.

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

Код события Prepare окна

// Подразумевается
// Если пользователь принадлежит группе, и поле Dataset - StatusComplaintID равно конкретному определённому значению, то блок frame group формы становится активным для этих пользователей.
// Вывод MessageBox - true - ..., true - ...
function wnd_ComplaintEditOnPrepare(Window) {
    ...
    if ( Dataset('StatusComplaintID') == compstatAnalized && IsContactIDInUserGroup(Connector.CurrentUser.ContactID, AdmUnitSupervisorCallGroup) ) { // Специалистам ГКС 2 линия могут осуществлять доразбор рекламации
    fgComplaintAnalysis.IsEnabled = true;
    //edtAppDescription.IsEnabled = false; пытался обыграть с отключением поля, но не могу дойти до него загрузив сервис в другом файле =) (пока просто не знаю как получить доступ к полю)
    var dsApplication = dlApplication.Dataset;
    dsApplication.Open();
    dsApplication.DataFields.ItemsByName('Description').IsReadOnly = true;		
    MessageBox(dsApplication.DataFields.ItemsByName('Description').IsReadOnly + " - свойство IsReadOnly\n" + dsApplication.DataFields.ItemsByName('Description').IsEnabled + " - свойство IsEnabled");
    }	
}

Далее событие DatasetDataChange

// Подразумевается
// Если в окошке в списке выбрали Статус с конкретным значением - то снимается свойство IsReadOnly, при любом другом значении вновь устанавливается.
function ds_ComplaintOnDatasetDataChange(DataField) {
    ...
    var Name = DataField.Name;
    var Value = DataField.Value;
    ...
    switch (Name) {
    ....
    case 'StatusComplaintID':
    var dsApplication = Services.GetNewItemByUSI('ds_ApplicationToNP');
    if (Value == compstatAppInNP) {
	dsApplication.DataFields.ItemsByName('Description').IsReadOnly = false;
	MessageBox(dsApplication.DataFields.ItemsByName('Description').IsReadOnly + " - свойство IsReadOnly\n" + dsApplication.DataFields.ItemsByName('Description').IsEnabled + " - свойство IsEnabled");
    } else {
        dsApplication.DataFields.ItemsByName('Description').IsReadOnly = true;
	MessageBox(dsApplication.DataFields.ItemsByName('Description').IsReadOnly + " - свойство IsReadOnly\n" + dsApplication.DataFields.ItemsByName('Description').IsEnabled + " - свойство IsEnabled");
    }				
}

* Под Application подразумевается заявка
* Под ApplicationToNP - заявка в смежное (neighbour) подразделение
Это не приложение =)

Свойства устанавливаются, но ожидаемого эффекта в самом окне не происходит
В Dataset у данного поля checkbox "только для чтения" - снят.
Возможно я чего то не знаю, прошу подсказать =)

Егор, добрый день.

Вы, наверное, запутались в двух (соснах)свойствах - IsReadOnly и IsEnabled. Первое свойство - это свойство DataField'а датасета, второе - это свойство контрола в карточке:

myControl.DataField.IsReadOnly = true;
myControl.IsEnabled = true;

В Вашем случае:

OnPrepare(Window) {
 
 
myMemo.DataField.IsReadOnly = true;
//myMemo.IsEnabled = false;
}
 
 
DataChange(DataField) {
 
if(DataField.Name == 'myListDataField' && !IsEmptyValue(DataField.Value)) {
myMemo.DataField.IsReadOnly = false;
//myMemo.IsEnabled = true;
}

Yegor, обратите внимание:
1. Как написал Дмитрий, у DataField'а нет свойства IsEnabled. Эта запись некорректна:

dsApplication.DataFields.ItemsByName('Description').IsEnabled

2. В функции ds_ComplaintOnDatasetDataChange Вы создаете новый экземпляр датасета. Нужно обращаться к уже существующему:

var dsApplication = dlApplication.Dataset;

Про свойства контрола я тоже помню, но в данном случае я его не использовал. (По совету Натальи проверил свойство IsEnabled как раз DataField'a)

Но всё равно при изменении свойства при смене пункта списка, поле не становится доступным для редактирования (возможно надо как то обновить окно, но подобных событий я не нашёл)

Если формально то пытаюсь достигнуть следующего
К примеру
есть список с языками

  • Русский
  • Английский

и есть два поля с текстом (оба недоступны для редактирования)
При выборе из списка пункт Русский соответствующее поле с текстом становится доступным для редактирования (сразу же), аналогично при выборе другого, поле блокируется, а с другого блокировка снимается. (Может быть пример не самый лучший, но суть описывает)
Возможно ли что то подобное сделать с окном в TerraSoft?
Повторюсь что при срабатывании DataChange свойство изменяется, но эффект не наблюдается.

"Бондарь Наталия" написал:Как написал Дмитрий, у DataField'а нет свойства IsEnabled. Эта запись некорректна:
dsApplication.DataFields.ItemsByName('Description').IsEnabled

Возьму на веру (Надо тогда SDK подправить) Вот вырезка на которую ссылался.
Свойство IDataField::IsEnabled

Признак активности поля.
IDL
__property VARIANT_BOOL IsEnabled;
Описание
Содержит значение "True", если поле набора данных является активным. Иначе содержит значение "False".

Если свойство содержит значение "False", то поле не участвует в формировании запросов, и значение данного поля получить и изменить нельзя.

С новым экземпляром скорее всего причина =) только сразу вопрос дилетантский) из скрипта датасета будет виден dlApplication???

"Litvyakov Yegor Vladimirovich" написал:из скрипта датасета будет виден dlApplication

Из скрипта датасета - нет. Для получения датасета используйте запись вида:

var dsApplication= DataField.ParentDataFields.ParentDataset;

"Litvyakov Yegor Vladimirovich" написал:Возьму на веру (Надо тогда SDK подправить) Вот вырезка на которую ссылался.

Вы правы, свойство IsEnabled у DataField действительно есть, немного ошиблась.
Но отвечает не за возможность редактирования поля, а за активность поля датасета (будет ли поле участвовать в формировании запроса).

В посте №1 я писала о свойстве IsEnabled контрола.

Упс :biggrin: точно.
Да и самая главная проблема. У DataField родительский Dataset не тот который нужен.
(При изменении поля одного датасета, надо разблокировать поле другого)
В такой ситуации я до существующего нужного Dataset'a не доберусь??? Или это возможно использую функцию GetSingleItemByCode?

Егор, вы все усложняете.
На OnPrepare заблокируйте нужные Вам контролы (или датафилды, тут по желанию) одной строкой.
А на датачендже просто в условии if(DataField.Name == 'myDropDownDataField') разблокируйте его опять таки одной строкой.
Тут я писал пример

А почему не создать обработчик события OnDatasetDataChange для компонента DatasetLink карточки?
В результате Вы сможете прописать ту же логику только обращаясь к компонентам DatasetLink (в данном случае к dlApplication).

Прописал то же самое что и выше, только в событии компонента DatasetLink, как предложила Наталия

"Бондарь Наталия" написал:А почему не создать обработчик события OnDatasetDataChange для компонента DatasetLink карточки?

В данном случае как раз получается без "танцев с бубном" получить Dataset не создавая новый экземпляр.

Наталия, Дмитрий, спасибо большое за помощь! Вы мне очень помогли в решении задачи и понимании системы =) (осталось куча вопросов, но куча разрешилась :mrgreen:)

С уважением
Егор

Показать все комментарии

Добрый день!
Понадобилось реализовать такую задачу:
В DataControlы карточки добавить появляющуюся при появлении значения в поле кнопку(за лупой, если это LookupDataControl), нажатие на которую очистит это значение и после этого кнопка снова исчезнет.
Данную задачу реализовываю при помощи ActionMenu, привязывая ее к DataField.Buttons динамически в событии OnDatasetDataChange и затем при удалении значения поля делаю DataField.Buttons = System.EmptyValue.
Так вот, все работает нормально, если удаляю значение кнопкой Delete с клавиатуры, кнопка появляется и исчезает нормально, но если значение удалять из события ActionMenuItemOnExecute (Sender.DataField.Value = null), вываливается ошибка List index out of bounds(2).
В чем может быть проблема?
Заранее благодарен!

Нравится

5 комментариев

Просто интересно, а чем Backspace не устраивал?

Вопрос к клиенту, наверное боятся мышь отпускать :wink:

Иван, реализуйте задачу немного иначе:
1. В функции dlDataOnDatasetDataChange пропишите логику скрытия amiActionMenuItem, например:

	if (FieldName == 'OwnerID') {
		if (IsEmptyValue (DataField.Value)){
	    amiActionMenuItem.IsVisible = false; 	
		}else{
		amiActionMenuItem.IsVisible = true;
		}
	}

2. В функцию обработки события OnExecute компонента amiActionMenuItem никаких изменений вносить не нужно.

Ошибка вызвана тем, что Вы находясь в уже вызванном обработчике события amiActionMenuItem, связанном с компонентом LookupDataField окна, пытаетесь сделать отвязку .

Спасибо Наталия, ситуация с ошибкой прояснилась.
Но проблема в том, что если сделать amiActionMenuItem.IsVisible = false, то он будет скрыт для всех DataField, которых очень много. А нужно это делать только для тех, в которых Value = null.

Вопрос решил обнулением Value по таймеру. Спасибо за наводку!

Показать все комментарии

Здравствуй, читатель. Давно мы не встречались с тобой.
Хочу поведать тебе об одной ошибке, выявление причины которой у меня заняло немало времени и дабы не наступать на эти грабли снова, внимай же голосу моему.

Если ты по некой неосторожности датафилду с типом Float присвоишь значение NaN, то система тебе ничего не скажет плохого. Однако, когда ты скажешь датасету: "Post!", система встретит тебя ошибкой вида:

TSObjectLibrary.DBDataset: Error posting record. Original error message: The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter 20 (""): The supplied value is not a valid instance of data type float. Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision

Эта ошибка возникает на стороне клиента, так что в профайлере ты ничего не увидешь.

Если ты, читатель, думаешь, что получить значение NaN очень сложно, то это не так. Достаточно написать:

var a = Dataset.Values('Subject');
var b = Dataset.Values('Divisor');
if (b != 0) {
   Dataset.Values('Result') = a / b;
};

Уважаемый написавший сей код не затруднил себя проверить, что a и b неравны null и в итоге при некоторых обстоятельствах (когда второй операнд = null) получил NaN. (опытный читатель воскликнет, что надо было использовать ValAsFloat вместо Values).

Спасибо за внимание и до новых встреч в эфире.

Нравится

Поделиться

12 комментариев

"Встреча с неведомым" и как ее избежать))
по идее ругаться система должна была еще при попытке присвоения NaN в тот самый датафилд - может стоит добавить отработку данного события этаким хитрым образом на уровень самого объекта Dataset, чтобы не ловить потом хитрые сообщения?

Нифига не понятно, но стиль - прекрасен!

"Репко Артём" написал:(опытный читатель воскликнет, что надо было использовать ValAsFloat вместо Values).

Я так понимаю, ValAsFloat нужно только в первых двух строчках? ;).

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

"Лабьяк Олег Игоревич" написал:Я так понимаю, ValAsFloat нужно только в первых двух строчках? ;).

Да, в последней строчке необязательно, хотя и не помешает.

При использовании метода ValAsFloat() нужно быть уверенным что в DataField имеет тип Integer или Float.

"Кривонос Максим" написал:При использовании метода ValAsFloat() нужно быть уверенным что в DataField имеет тип Integer или Float.

Более того, нужно быть увереным, что переменная Dataset является объектом, реализующим интерфейс IDataset.

Артём, +1 ))).

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Я был не прав, тип DataField'a не обязательно должен быть Integer или Float, главное чтоб его значение было подходящим.

Воспроизвел ситуацию, но сообщение появилось немного другое:
TSObjectLibrary.DBDataset: Error posting record. Original error message: A floating point exception occurred in the user process. Current transaction is canceled

Кстати, для воспроизведения хватило бы написать:

Dataset.Values('Result') = NaN;

А в текущем примере если немного изменить, то ошибка бы не появилась:

var a = Dataset.Values('Subject');
var b = Dataset.Values('Divisor');
if (b) {
   Dataset.Values('Result') = a / b;
};

Думаю какую проверку нужно добавить в ядро. Если передают NaN конвертировать в null?

"Александр Кравчук" написал:Dataset.Values('Result') = NaN;

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

"Александр Кравчук" написал:Думаю какую проверку нужно добавить в ядро. Если передают NaN конвертировать в null?

Я бы лучше исключение генерировал. Вряд ли человек, написавший Dataset.Values('a') = 5 + a / b (где b равно null), ожидает в результате увидеть null в поле.

"Репко Артём" написал:Я бы лучше исключение генерировал.

Согласен, наверное так и сделаю.

Дякую Артем!
Ніколи не знаєш, коли така інформація стане корисною. І ось цей час настав.

Показать все комментарии

Здравствуй, дорогой читатель.

В нашу редакцию часто приходят письма:
почему, если я создал FloatDataField (Поле с дробным значением) размером 15, сослал его на ConstColumn (Колонку-константу) с DataType (Типом данных) = Float (Дробное число) и заполнил это поле значением большим, чем 2147483647, я получаю ошибку

   TSObjectLibrary.DBDataset: Invalid value for field '...'

Спешим ответить: причина в том, что ваше поле, независимо от указанных вами типов, было распознано как Integer (создан внутренний объект TField с типом значения Integer). Фокус в том, что тип поля для константных колонок определяется по начальному значению в этом поле, например:

если начальное значение NULL, то тип поля Integer;
если начальное значение '', то тип поля String;
если начальное значение 3 , то тип Integer;
если начальное значение 3,3 , то тип поля Float.

То же самое касается SQLTextColumn, в которых мы указываем константные значения.
Если хотим редактируемое дробное поле, которое ссылается на колонку-константу с пустым (нулевым) начальным значением, то единственный выход, который я вижу - это создать SQLTextColumn с значением 0.0 (дробный ConstColumn со значением 0,0 не проходит, т.к. значение преобразуется в 0 и поле снова считается Integer).

Нравится

Поделиться

4 комментария

Интересный материал. Теперь, если столкнусь с такой проблемой, не буду писать письма в редакцию, а сразу все сделаю правильно:smile:

Вот это да! Спасибо за такое исследование и за пример для типа Float.
А как мне сделать так, чтоб поле распозналось как дата/время и при этом было пустое?

"Кривонос Максим" написал:
А как мне сделать так чтоб поле распозналось как дата/время и при этом было пустое?

Создать SQLTextColumn с текстом

CAST(NULL AS DATETIME)

Спасибо

Показать все комментарии