Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
TIWComboBox + OnAsyncChange + ItemsHaveValues
#1
C++ Builder 11.0 / IW 15.2.47

TIWComboBox ItemIndex is not always updated correctly. 

For example: TIWComboBox Items populated with

A=1
B=1
C=1
D=2

and ItemsHaveValues = true so that only Names[] values A, B, C, D are visible. 

When selecting:
A, ItemIndex == 0 // correct
B, ItemIndex == 0 // incorrect
C, ItemIndex == 0 // incorrect
D, ItemIndex == 3 // correct

The ItemIndex seems to be affected by the Values[] column. 

Desired behavior is for ItemIndex to be updated to the true selection offset regardless of the Items content.

Demo attached.


Attached Files
.zip   IWTEST.zip (Size: 1.61 KB / Downloads: 1)
Reply
#2
Before even testing it... values shouldn't be the same for different items. The value is the KEY of the list and there is no way to distinguish one from the other if you have identical values for two different items.

If you want that 2 different items behave the same in your event handler, you need to treat 1, 2 and 3 the same, not giving first, second and third item the same value "1".

Imagine a LookupComboBox (from VCL, not IW) where all KeyValues of the list have the same value?
Reply
#3
(11-29-2021, 03:32 PM)MJS@mjs.us Wrote: C++ Builder 11.0 / IW 15.2.47

TIWComboBox ItemIndex is not always updated correctly. 

For example: TIWComboBox Items populated with

A=1
B=1
C=1
D=2

and ItemsHaveValues = true so that only Names[] values A, B, C, D are visible. 

When selecting:
A, ItemIndex == 0 // correct
B, ItemIndex == 0 // incorrect
C, ItemIndex == 0 // incorrect
D, ItemIndex == 3 // correct

The ItemIndex seems to be affected by the Values[] column. 

Desired behavior is for ItemIndex to be updated to the true selection offset regardless of the Items content.

Demo attached.
>>Before even testing it... values shouldn't be the same for different items.

I don't see any requirement for that in the way TStringList or TIWStringList work.  IWCombo may be designed that way but's it's a restriction that radically changes the behavior based on ItemsHaveValues=true or ItemsHaveValues=false.  I think with ItemsHaveValues=true the IWCombo should display only the Names[] strings, then give the correct ItemIndex when a selection of an item occurs so that the correct Values[] can be returned.  Right now an incorrect ItemIndex can be returned (note the property is named ItemIndex not  FirstUniqueValueIndex).


>>The value is the KEY of the list and there is no way to distinguish one from
>>the other if you have identical values for two different items.

You don't want to search just the Values[] to determine uniqueness but search for the whole NAME=VALUE string itself (the Item). 


>>If you want that 2 different items behave the same in your event handler, you
>>need to treat 1, 2 and 3 the same, not giving first, second and third item the
>>same value "1".

My use case:  IWCombBox populated with many 'ACCOUNT_NUM=COUNTYID' strings. COUNTYID can be mostly duplicates but not always. With ItemsHaveValues=true ACCOUNT_NUM displays, COUNTYID does not but I can apply it to the database query based on IWCombBox selection.  Seems like a reasonable use case.


>>Imagine a LookupComboBox (from VCL, not IW) where all KeyValues of the list have
>>the same value?

Those are two different components with their own functionality - don't think that's a good comparison.  I have a workaround implemented so not waiting on a fix but think this is a design flaw in IWComboBox.
Reply
#4
This control mirrors the functionality of the VCL one and uses many of the same routines. The way Value/Key pairs work in RTL goes back to Delphi 1.0 in the mid 90s.

For things with duplicate values, ItemsHaveValues and the Delphi RTL key/values, its has always been this way. IWComboBox mirrors TComboBox in behavior as it shares the same RTL routines.

I suggest using alternate methods or keys in such cases as would need to be done with TComboBox as well. There are many ways, but one is to simply store a parallel 1:1 TStringList which contains your information matched up by index as a private or protected field. This is often done this way in normal VCL apps as well.

"I don't see any requirement for that in the way TStringList or TIWStringList work"

TStrings has built in methods for the keys and values, and its how they work. They dont deal with duplicates.

http://www.delphigroups.info/2/6/325181.html
Reply
#5
Let's circle back to points in my first post:

1.  The ItemIndex seems to be affected by the Values[] column.

2.  Desired behavior is for ItemIndex to be updated to the true selection offset regardless of the Items content.

We should focus on these points as opposed to how ItemsHaveValues was implemented.


>>[KUDZU]: IWComboBox mirrors TComboBox in behavior as it shares the same RTL routines.

If I add these to a TComboBox Items property:

A=1, B=1, C=1, D=2
or
'','','',''

the correct ItemIndex is always returned on selection, ItemIndex is not dependent on Items content.  ItemIndex always means selected offset.



>>[KUDZU]: TStrings has built in methods for the keys and values, and its how they work. They dont deal with duplicates.

If IWComboBox/ItemsHaveValues=true only uses TStrings built-in methods and cannot return a ItemIndex as true selected offset then I guess it needs
more logic beyond TStrings.
Reply
#6
(12-18-2021, 04:58 PM)MJS@mjs.us Wrote: Let's circle back to points in my first post:

1.  The ItemIndex seems to be affected by the Values[] column.

2.  Desired behavior is for ItemIndex to be updated to the true selection offset regardless of the Items content.

We should focus on these points as opposed to how ItemsHaveValues was implemented.


>>[KUDZU]: IWComboBox mirrors TComboBox in behavior as it shares the same RTL routines.

If I add these to a TComboBox Items property:

A=1, B=1, C=1, D=2
or
'','','',''

the correct ItemIndex is always returned on selection, ItemIndex is not dependent on Items content.  ItemIndex always means selected offset.



>>[KUDZU]: TStrings has built in methods for the keys and values, and its how they work. They dont deal with duplicates.

If IWComboBox/ItemsHaveValues=true only uses TStrings built-in methods and cannot return a ItemIndex as true selected offset then I guess it needs
more logic beyond TStrings.

>> Let's circle back to points in my first post:

Agreed.

>> 1.  The ItemIndex seems to be affected by the Values[] column.

That's correct and I would expect so. Remember that ItemIndex is a read//write property but in order to fully understand it, you need to separate each part, the getter, and the setter. 

When you think about the getter, ItemIndex shows the offset of the *selected* item but - and here is the catch - once the selected *key* (the value) is received from a browser request, the selected offset (or ItemIndex) is determined searching for a match in the Values[] column.

>> the correct ItemIndex is always returned on selection, ItemIndex is not dependent on Items content

I don't agree here. As I explained above, the user selection (that happens on the browser) does not select an element position (or index) but instead, it selects an element *key* (or the value). The value is used to "calculate" the ItemIndex on the server-side.

I'll check your example once more and see If I have any other suggestion to make it work as you want, but the ComboBox behaves that way by design.
Reply
#7
>>The value is used to "calculate" the ItemIndex on the server-side...
>>>>[KUDZU]: IWComboBox mirrors TComboBox in behavior as it shares the same RTL routines.

I think by definition ItemIndex is always a true offset in the VCL sense.


>>I'll check your example once more and see If I have any other suggestion to make it work as you want..


Not necessary, I had a fix in place before I originally posted.
Reply
#8
(12-20-2021, 11:46 AM)MJS@mjs.us Wrote: >> I think by definition ItemIndex is always a true offset in the VCL sense.

Yes, it is.  But the point is, on the browser side you have this:

<select id=IWCOMBOBOX1>
<option SELECTED="" VALUE="-1">-- No Selection --</option>
<option VALUE="1">A</option>
<option VALUE="1">B</option>
<option VALUE="1">C</option>
<option VALUE="3">D</option>
</select>

The above is the exact representation of such ComboBox and how IW renders it.

Then, when you pick any item from the list, the browser sends a request to the IW server containing the chosen *VALUE* (as long as you have an OnChange/OnAsyncChange event assigned to it, of course):

Let's say you picked the third item. Then IW will receive a request saying that IWComboBox1 selected *VALUE* is 1.

How to decide which of the "1"s above is the one that the user picked? Without testing it I'd say that IW will pick option A as the chosen value (because it looks sequentially within the list, from top to bottom, although it could also do the other way without sacrificing the correctness of the algorithm).

You see why VALUE must be unique?
Reply
#9
>>You see why VALUE must be unique?

Yep, I do.  But in order not to break ItemIndex for VCL behavior compatibility I guess I would append something like '_IWN' (N being a hex value integer representing item index) to the value then strip it after it returns from the async / refresh call.  Could be done transparently at the component level.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)