I have a table in a report and a textbox that changes its background color based on the value(s) in the table. Right now I have the background color expression for the textbox set to:
=iif(Me.Value = ReportItems![NewValue].Value, "Yellow", "Transparent")
"NewValue" is the name of one of the columns in the table. The above works fine if the textbox value is in the very first row in the "NewValue" column, but not otherwise.
How do I fix this so it will work if the textbox value shows up in any row in the "NewValue" column?
Sorry, I'm a little new to Reporting Services and haven't seen any functions for table controls.
Instead of ReportItems![NewValue].Value, you can also use ReportItems("NewValue").Value, by the way
I finally got this working yesterday thanks to this blog post:
http://mpasharp.spaces.live.com/blog/cns!5BA71A558863C810!191.entry?sa=340192646
I basically did what he did in the post, modified slightly for my report. I also added a function for getting the row index of the value I was looking for (variables are a little different in mine).
Public Shared Function GetChangedValueIndex(txt As String) As Integer
Dim counter As Integer = 0
For Each s As String In ChangedValueList
If s = txt Then
Return counter
End If
counter += 1
Next
Return -1
End Function
The other caveat is that calling the function to add a value to the array has to occur earlier in the report than anywhere you want to check for it. The table I was working with is actually at the end of the report (and can't be moved for requirements reasons) so I made a copy of that table, moved it to the top of the report, and set it to be hidden.
Unbelieveable that there isn't an easier way to do this.
Related
I created many option groups in MS Access 2013 and I am trying to populate my table according to what is selected in the option group. So, if the user selects option 1, I want "the text" not its value ex: "1" stored in my table. I tried the following code in AfterUpdate() event and it works fine:
Private Sub Frame49_AfterUpdate()
Dim D As Integer
Select Case Me![Frame49]
Case 1
Me![Name] = "text"
D = 1
Case 2
Me![Name] = "text1"
D = 2
Case 3
Me![Name] = "text2"
D = 3
Case 4
Me![Name] = "text3"
D = 4
Case 5
Me![Name] = "text4"
D = 5
End Select
DoCmd.RunCommand acCmdSaveRecord
Rem D = Frame49.Value
End Sub
but when the end user answers the first question and tries to answer the next question, all options of the previous question get selected. How do I fix this?
Here is the file to see what I mean:
https://drive.google.com/open?id=1WjrAhXCnk961mxBuxS3RYqOUpPA_GsyL
Thanks in advance.
even though the option group only takes numeric values, you can achieve what you want by hard coding the values using if statements e.g
If Frame5 = 1 Then orukolook = "okay"
If Frame5 = 2 Then orukolook = "right"
If Frame5 = 3 Then orukolook = "fine"
orukolook is the textbox control that you want the texts to be inserted, so if the first option of the option group is selected,the text "okay" will be inserted into the textbox control, if second option then the text "right" will be inserted.
The values hard coded in the place holder oruko look,e.g okay,right, fine are the labels associated to each value in the option group.
OptionGroup frame and associated buttons/checkboxes must have a number value. Therefore OptionGroup frame must be bound to a number type field. If you want controls to reflect selection in a text field, then need code to set UNBOUND OptionGroup frame with corresponding number value. In other words, convert saved text back to number value. Code would most likely need to be in form Current event. Something like:
Me.Frame49 = Switch([Name]="text",1, [Name]="text1",2, [Name]="text2",3, [Name]="text3",4, [Name]="text4",5)
Alternatively, save number value to number fields. Text equivalent is provided by labels on form. Use lookup tables to provide text equivalent on reports or calculate the equivalents with expressions in query or textboxes. An expression like:
Choose([Name], "text", "text1", "text2", "text3", "text4")
BTY, Choose() expression can be used in place of Case structure in your original code.
Me![Name] = Choose(Me.Frame49, "text", "text1", "text2", "text3", "text4")
Also recommend using radio (option) buttons instead of checkboxes.
Other alternatives are comboboxes and listboxes instead of option groups.
Advise not to use reserved words as names for anything. Name is a reserved word. Also, avoid spaces and punctuation/special characters in naming convention.
Frame49 is bound to a database field.
When the user clicks a checkbox, the field's value (along with Frame49's value) is set to an integer.
You then change the database field's value to a string.
This causes Frame49's value to be set to that string.
Since that is an invalid value for an Option Group, all the related checkboxes show as a solid black square, representing an indeterminate state. That is not the same as a checkmark, so your observation "all options of the previous question get selected" is incorrect.
The simplest way to do what you want is to use a 1-column ListBox instead of an Option Group. You can size each ListBox so that it shows all the options as text strings.
When the user clicks an "option" to select it, the corresponding text string will be written to the database, with no VBA code involved.
When the user goes back to a previous record, the ListBoxes will all show the proper selections.
If you don't want to change how your form looks, then you must do as others suggested, and make Frame49 unbound, i.e. set its Control Source to blank.
Then when you set the database field's value to a text string, Frame49's value will remain as an integer.
If you want the ability to go back and edit earlier records, you can do it but it is beyond what I can answer here.
I have a lookup listbox which is programmed to allow the user to find a specific record/help topic from the list and view it. Now when the list box is used the where clause locks in the record and the first, previous, next, last buttons freeze up and you cannot use them to go to a record. Is there a way to free up the functionality of the buttons to navigate through the records along with the where clause to select.
Here is the code that operates the listbox selections:
Private Sub List35_AfterUpdate()
Dim myTopic As String
myTopic = "Select * from FormsHelpTable where ([ID] = " & Me.List35 & ")"
Me.Form.RecordSource = myTopic
Me.Comment.Requery
End Sub
I believe since the where clause locks in the selection in the box it does not allow navigation from other controls to interfere. What might be a way around this?
You get the runtime error:
You can't go to specified record.
It appears not to be reading the other record in the source table named Help once it updates using the listbox.
Instead of changing the recordset (this is the 'pool' of records which the form could display), you just need to go to the record the user selects from the listbox.
Method 1 (probably the easiest way if your listbox is in the same order as the records of your form)
Use this code:
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
End Sub
You need to ensure that:
The recordset of the form is ordered the same as the listbox. So, for example, you could order both by ID, or by Title.
Note that the +1 comes from the fact that the ListIndex starts at 0, whereas the record indexes start at 1.
Method 2
Ensure each record's Title is unique (set No Duplicates on this field).
Change your listbox to return the Title of the record, rather than it's ID.
Then use this:
Private Sub lstSelect_AfterUpdate()
Me.Title.SetFocus
DoCmd.FindRecord Me.lstSelect
Me.lstSelect.SetFocus
End Sub
Things to note:
It works by searching the field with focus for the string specified. That's why we have to SetFocus on the Title textbox on our form.
We could use ID instead, (which would mean we could have duplicate titles if we wanted), but then we would have to have an ID control on the form to SetFocus to. You can't hide this control either, because it needs to have focus whilst using FindRecord.
Update: Method 1 with reverse-selection
Add an Event Procedure in the Form_Current event, with this code. Then update the code in the lstSelect_AfterUpdate procedure as shown after.
Private Sub Form_Current()
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Note that, depending on how your lstSelect is set up, it may be Column(1, Form.CurrentRecord - 1) instead. Read on for details!
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Explanation of new lines:
The Form_Current event fires every time we go to a new record. We need to look at the index of the record (ie. the position of it in the recordset), which we get by using Form.CurrentRecord. We then want to make the listbox select that record. However, we can't use me.lstSelect.ListIndex as before, because that is a read-only property (we can access it to read it, but we can't set it).
Therefore, we use me.lstSelect.Column(colNum,rowNum) instead, where we specify a column number and a row number. If your listbox has two columns (eg. ID and Title), we want to choose the second column. The index starts at 0, so we would use a value of 1. If, like my lstSelect, you only have one column (Title) then we use 0. Note: it doesn't matter if a column is hidden (ie. has width 0). It still 'counts'.
The row number is Form.CurrentRecord - 1. Remember that the forms recordset index starts at 1, but the index of our listbox starts at 0; hence the - 1.
So why do we need a duplicate of this new row in the AfterUpdate event? Try and comment it out to see what happens if we don't put it in. It's has to do with the Form_Current event firing after we use the listbox.
I fixed this issue with a union clause in the SQL lookup code. The UNION ALL clause and the following union on the table used in the other part had allowed all the records to be used.
i have a report with parameter is the year i can select a multiple value: for example i selected 2005,2006,2007
when i click in view report i get this result
i added some custom code to add value in arraylist
Dim values As System.Collections.ArrayList
Function AddValue(ByVal newValue As Integer)
If (values Is Nothing) Then
values = New System.Collections.ArrayList()
End If
values.Add(newValue)
End Function
Public Function GetArray(Item as Integer)
return values(Item)
End Function
i added my code in my matrice this is the result
The first row i got the right anwer but the other rows are false answers this is the resut what i need
Without RDL details regarding your expressions - it is difficult to answer your question. What are your expected results? What is the exact input and output you are expecting? Please provide samples.
In this scenario, it seems the issue is in your custom code. Once you return the result at the end of first row. The variable(called "result") keeps the "66" and it was never overwritten so that it always shows "66". In Reporting Services, it generates cells from left to right, top to bottom. So you need to pass the first column (HP, DELL, Acer) as argument in your function and use a variable (called "previous")to receive this value. Always do the judgment at the beginning of the function, if the passing argument is not equal to the "previous". You need to clear the "result" variable.
I have a function which return a list of countries as data table. How do I add these row values to a combo box?
For Each row as DataRow in fooDataTable.Rows
combobox.Items.add(row)
Next
Some how this does not fill up the values on my combo box. The datatable returns 100 rows. Each row has 2 columns. I am trying to add all the 100 datarows with the first column. Any help would be greatly appreciated.
A DataRow is an object and while objects can be added to a Combo or ListBox, in this case the result is not very useful. When you store an Object in .Items, the result of the .ToString function is what displays. In this case it will just display System.Data.Datarow
The best solution is what LarsTech suggested and use the existing datatable as the datasource. This is economical because there is nothing new created for the CBO:
ComboBox.DataSource = fooDataTable
ComboBox.DisplayMember = "column name in DT"
Another way is to modify your loop:
combobox.Items.Add(row("col name").ToString)
This adds the data from the column name to the cbo. If this was something like peoples names and you wanted to show First and Last name:
combobox.Items.Add(String.Format("{0}, {1}", row("LastName").ToString,
row("FirstName").ToString))
This is similar except we are formatting the contents of both columns as we add it to the CBO.
Still another way is to create a class object for each row which returns what you want to display via the ToString override; and add them to the CBO, but that is overkill in this case, given the economy of the first alternative.
I'm using an Infragistics UltraWinGrid with a column of drop-down boxes. I don't want the user to be able to select the same value for multiple rows in that column. Is there a simple (or heck, I'd settle for advanced) way to do this?
I'm using VB.NET
-EDIT-
I tried setting a filter on the data source for the drop-down box. But when I did that, the values in the other boxes in that column started disappearing (not the values themselves, but the descriptions that they were supposed to represent, so instead of reading "Information", it just said "1"). All of the cells in a column refer to the same combo box, so if you filter out a value from the data source for one of them, you filter it out for all of them.
I'm currently trying to catch a CellChange event and check against all other currently-used values. If it was already used, I would put up a message saying as much and revert back to the old value. However, the value comes back as the previously-saved one, so... not helpful. About to see if I can use the "text" property.
Since you're using Infragistics, you could use an UltraDropDown which is bound to a DataTable (or something similiar) which you can add a "Selected" column in addition to a column holding the values you want to show.
As each value is selected (via AfterCellUpdate or AfterCellListCloseUp for instance), you could update the "Selected" column in that data source and use a column filter to only show items which haven't been marked as selected. That way as items are selected or removed, the contents of the drop-down would be automatically updated.
To clear the selected flag from the old value, you can use the BeforeCellUpdate event to access the cell's current value then perform a lookup on the data source bound to the UltraDropDown using that value to clear the flag.
Solved it:
The trick was to use BeforeCellUpdate whose BeforeCellUpdateEventArgs has a "NewValue" and a "Cancel" member. I just look through all of the items in the column to see if any of them match the new value. If one does, I notify the user and cancel the operation.
And that's it. Here's the code:
Private Sub myUltraWinGrid_BeforeCellUpdate(ByVal sender As Object, ByVal e As Infragistics.Win.UltraWinGrid.BeforeCellUpdateEventArgs) Handles myUltraWinGrid.BeforeCellUpdate
If e.Cell.Column.Key = "myColumn" Then
Dim newValue As Integer = CInt(e.NewValue)
For Each row As Infragistics.Win.UltraWinGrid.UltraGridRow In myUltraWinGrid.Rows
If row.Cells("myColumn") IsNot e.Cell _ 'So I'm not checking against the current cell
AndAlso CInt(row.Cells("myColumn").Value) = newValue Then
MsgBox("That value has already been used in this column")
e.Cancel = True
End If
Next
End If
End Sub