Problem with Write Custom Function in reportViewer repot - reportviewer

I want to use of a custom function in reportviewer's expression report .
I wrote this function in code tab section in report's property.
I want to use of this function in my feild's expression but when i write "Code" and put after that "." , intellisense in report's expression does not show me my function.
Public Function FarsiNumber(ByVal str As String) As String
Dim s As String = ""
Dim ch() As Char = str.ToCharArray
For Each c In ch
If IsNumeric(c) Then
s += CChar(ChrW(1728 + CInt(AscW(c))))
Else
s += c.ToString
End If
Next
Return s
End Function
any body can show me an example.
thanks

The Intellisense doesn't catch my custom functions either. But you can still use them.
In your case, you can use Code.FarsiNumber() in your expressions in your report

Related

SSRS Group Variables SUM & VB.NET Custom Code

I have an SSRS report built using group variables with expressions that do field calculations. The group varaibles are providing correct results between 3 datsets using lookups, arithmatic, and logic operations.
I need to SUM total the results of the variable textbox expressions in the tablix footer. But variables will not work in this way and when I try different expressions in the tablix footer I get errors.
So I did online search of summing group variables and I came to custom code solution using VB.NET variables with functions to aggregate then display the values. But the custom code is not quite working. Please see the custom code at the bottom of the page. And here are some issues I've observed
Custom Code issues
If I use variable as Public Dim the total values changes to 0 when exported to excel (e.g.- "1,214,284" on the screen; "0" when exported to excel.)
If I change declare the variables as Public Dim to Public Shared Dim then the values on screen are the same and they will export to excel.
The problem is Public Shared Dim seems to work great in Visual Studio. But when executed on the Report Server, the variable accumulates every time the report is executed (i.e., ExecEvent #1: "150 value" on the screen & excel; ExecEvent #2: "300 value‬" on the screen & excel; ExecEvent #3: "450 value‬" on the screen & excel).
Any help? How can I make these values aggregate and export? How to get the custom code VB variables to behave correctly. Particularly the variable initialization on the server getting correctly set and reset.
Custom Code correction notes
In the "add" function I added return thisValue to fix an issue where the details variable values with blank (not printing)
References
SSRS Summing Group Variables outside of the group
SSRS code variable resetting on new page
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/d4a3969a-f3fc-457b-8430-733d7b590ff6/use-reportitems-to-sum-all-textboxes-in-a-tablix?forum=sqlreportingservices&prof=required
TablixDesign-WithGroupVaraibles
Group row, Group footer row
Tablix Footer: group variable expression errors outside of group
NOTE: These expressions are not allowed
Variables!varExpenditureLifetime.Value --ERROR: Expressions can only refer to a Variable declared within the same grouping scope, a containing grouping scope, or those declared on the report. Letters in the names of variabels must use the correct cast.
Sum(Variables!varExpenditureLifetime.Value) --ERROR: Variables cannot be used in aggregate functions
REPORT CODE:
Group Variable ("varLWSBegin_LifetimeExpense")
= Code.addLWSBeginLifetimeExpense(CDbl(
IIF(Parameters!boolUseLwsBalance.Value = false, 0,
Lookup(Fields!ProjectId.Value, Fields!ProjectId.Value, Fields!LWSBegin_LifetimeExpense.Value, "dsCAPEXAmountsCustomDataUpload"))
))
Tablix group row
Variables!varLWSBegin_LifetimeExpense.Value
Tablix footer row
Code.getTotalLWSBeginLifetimeExpense()
VB.NET Custom Code
'
' Add group variable values to an external variable declared on the VB Code.
' In Tablix Group Properties variable the value will be the call to the addValue function
' Then on your textbox you call the getValue function:
' Group Var: Code.addValue(Fields!my_field).
' Textbox: Code.getValue()
'
' variable1, addTotalBudget, getTotalBudget
' variable2, addLWSBeginLifetimeExpense, getLWSBeginLifetimeExpense
' variable3, addExpenditureLifetime, getExpenditureLifetime
'
'TEMPLATE
Public totalMyField2 as Integer
Public totalMyFieldName as Integer
Public Function addMyFieldName(ByVal thisMyFieldName AS integer)
totalMyFieldName = totalMyFieldName + thisMyFieldName
End Function
Public Function getMyFieldName()
return totalMyFieldName
End Function
'MyVariables
Public Shared Dim totalTotalBudget as Integer
Public Shared Dim totalLWSBeginLifetimeExpense as Integer
Public Shared Dim totalExpenditureLifetime as Integer
Public Shared Function Initialize()
totalTotalBudget = 0
totalLWSBeginLifetimeExpense = 0
totalExpenditureLifetime = 0
End Function
'Functions
Public Function addTotalBudget(ByVal thisValue AS Integer )
totalTotalBudget = totalTotalBudget + thisValue
return thisValue
End Function
Public Function addLWSBeginLifetimeExpense(ByVal thisValue AS Integer )
totalLWSBeginLifetimeExpense = totalLWSBeginLifetimeExpense + thisValue
return thisValue
End Function
Public Function addExpenditureLifetime(ByVal thisValue AS Integer )
totalExpenditureLifetime = totalExpenditureLifetime + thisValue
return thisValue
End Function
Public Function getTotalBudget()
return totalTotalBudget
' Dim myval as Integer = totalTotalBudget
' totalTotalBudget = 0
' return myval
End Function
Public Function getTotalLWSBeginLifetimeExpense()
return totalLWSBeginLifetimeExpense
' Dim myval as Integer = totalLWSBeginLifetimeExpense
' totalLWSBeginLifetimeExpense = 0
' return myval
End Function
Public Function getTotalExpenditureLifetime()
return totalExpenditureLifetime
' Dim myval as Integer = totalExpenditureLifetime
' totalExpenditureLifetime = 0
' return myval
End Function
'<END>
Easiest approach to be able to use variables like you are trying to is to use Report Variables instead of Group Variables. If you use Report Variables, it can be accessed from any scope.
You might have to change your dataset a little bit so that the aggregation is unmistakably grouped when calculated at the report level. I could not really guide you with that because I don't know your data like you do. But as an easier route to the scope of your aggregation, check this SO question. You can use your table group as the scope of your aggregate functions.
I've had to do something along the lines of what you are trying to accomplish and Report Variables came to the rescue for me. Let me know if this would work in your scenario.

When is it suitable to use a Sub-Procedure instead of a function?

In my class today I was told change some of my sub-procedures to functions, and when I asked why it's better my teacher struggled to answer, generally, i've always thought that functions should only really be used when a value is returned. In the two examples below; is there one method that should be used over the other, or does it not matter? And if it does matter why?
Thanks in advance.
Method 1 (Sub-Proc):
Sub EncryptString(ByVal unkString, ByRef encryptedString)
For i = 1 To Len(unkString)
encryptedString += "*"
Next
End Sub
Method 2 (Function):
[In main I assign the variable "encryptedString" to this function].
Function encryptString(ByVal unkString) As String
For i = 1 To Len(unkString)
encryptString += "*"
Next
End Function
You've misunderstood what they're trying to tell you. In your Function example there is no difference. What your teacher is expecting is like this:
Function EncryptString(ByVal unkString) As String
Dim encryptedString As String = ""
For i = 1 To Len(unkString)
encryptedString += "*"
Next
Return encryptedString
End Function
This is a cleaner and more reusable way than modifying a field, an argument passed ByRef, or the underlying variable of the function
Your example show one of the multiple reason, who initialize the data is unclear. With your sample code, the first option would append to the passed string while the second would create a new string.
The first method would have to specify if it needs an empty string or explain why it appends. While the second method clearly show that a new string will be returned.
Sub Main()
Dim u, e As String
u = "123"
e = "123"
EncryptString1(u, e)
Console.WriteLine(e) ' Display: 123***
u = "123"
e = "123"
e = encryptString2(u)
Console.WriteLine(e) ' Display: ***
Console.ReadLine()
End Sub
Sub EncryptString1(ByVal unkString As String, ByRef encryptedString As String)
For i As Integer = 1 To Len(unkString)
encryptedString += "*"
Next
End Sub
Function encryptString2(ByVal unkString As String) As String
encryptString2 = ""
For i As Integer = 1 To Len(unkString)
encryptString2 += "*"
Next
End Function
Please have option strict on. Also, personally, I rather create a variable instead of using the function name, use .Length instead of Len() and concatenate with & instead of +.
Function encryptString3(ByVal unkString As String) As String
Dim encryptedString As String = ""
For i As Integer = 1 To unkString.Length
encryptedString &= "*"
Next
Return encryptedString
End Function
Or just use the New operator of the String class.
Dim encryptedString as New String("*"c, unkString.Length)
Well, when I was learning this stuff, it was always to use functions to calculate values and subs to do other stuff. I guess for something very general, it doesn't really matter which methodology you use, as you have illustrated in your example. See the link below for further discussion on this topic.
http://analystcave.com/vba-function-vs-vba-sub-procedures/

VBA CSng(string) wrong format

I read in a node from a xml file and try to parse one of its attributes to a single.
Dim x_coord_single As Single
Dim x_coord_string As String
x_coord_string = node.Attributes.getNamedItem("x_coord").Text
x_coord_single = CSng(x_coord_string )
After i assign x_coord_string it equals "9.0647"
But the CSng function returns 90647
I would expect x_coord_single to be 9.0647.
I tried CSng("9.0647") directly but it's the same outcome.
Any suggestions on why it is not?
I'm working with MS Access 2010 if it affects this anyhow.
Try like this:
Public Function fnStrChangeCommas(ByVal myValue As Variant) As String
fnStrChangeCommas = Replace(CStr(myValue), ".", ",")
End Function
x_coord_single = CSng(fnStrChangeCommas(x_coord_string ))
It should work, because your language regional settings use , as a decimal separator and the VBEditor uses the ..
To see the separators your system is using in VBA, run the following code:
Public Sub TestMe()
Debug.Print "Decimal separator: "; Application.DecimalSeparator
Debug.Print "Thousands separator: "; Application.ThousandsSeparator
End Sub
If it returns this:
Decimal separator: ,
Thousands separator: .
Then you may consider using the fnStrChangeCommas function.
The simple and universal method is to use Val:
x_coord_single = CSng(Val(x_coord_string))

Excel VBA: Failed to pass a string array to a Function

VBA Beginner here.
I am trying to pass an array of strings from a subroutine to a function which will then modify each string in the array. However I get the "Type:array or user-defined type expected" error message.
I have tried redefining different data types for the array so it is aligned with the data type entered in the function but to no avail.
Hope you can help! THank you so much!
Below is the dummy code:
Sub text()
Dim haha() As Variant
haha = Array("Tom", "Mary", "Adam")
testing (haha())
MsgBox Join(haha, " ")
End Sub
Function testing(ByRef check() As String) As String()
Dim track As Long
For track = LBound(check) To UBound(check)
check(track) = check(track) & " OMG"
Next
End Function
In orignial code, a string is not the same variant (I believe they both would need to be variant? someone can verify), you dont need the brackets after testing, only need brackets if you are setting to another value e.g.
haha2 = testing(haha())
Below code should be ok
Sub text()
Dim haha()
haha = Array("Tom", "Mary", "Adam")
testing haha()
MsgBox Join(haha, " ")
End Sub
Function testing(ByRef check()) As String
Dim track As Long
For track = LBound(check) To UBound(check)
check(track) = check(track) & " OMG"
Next
End Function
You have a few errors in your code:
There are two ways of invoking methods:
1) with Call keyword - in this case you must give all the parameters in brackets:
Call testing(haha)
2) without Call keyword - in this case you just give your parameters after the name of function:
testing haha
In your code you combined both of them and this is syntax error.
If you pass an array as a parameter to function you don't need to put brackets like that: testing (haha()).
The proper syntax is:
testing(haha)
Function testing requires as a parameter an array of String type, you cannot pass object of other type instead since it causes compile error Type mismatch. Currently you are trying to pass variable haha which is of Variant type.
You can change the type of haha variable to array of strings (to avoid the error described above):
Dim haha() As String
However, in this case you cannot assign the value of function Array to it, since the result of this function is of Variant type.
You would have to replace this code:
haha = Array("Tom", "Mary", "Adam")
with this:
ReDim haha(1 To 3)
haha(1) = "Tom"
haha(2) = "Mary"
haha(3) = "Adam"
A couple of suggestions to improve your code:
Dim haha() As String
You define the type of the entry in the array, not the array itself. Use the way mentioned by mielk to fill the array.
Function Testing(byref check as variant) As String
This will avoid problems with undefined variables. Not clear why you feel that the function should return a string though. Maybe even convert to a Sub instead.

Function convert cyrillic to latin

I am trying to create custom convert cyrillic to latin text function in VB.net. I've never tried to make a custom function so I don't know what I am doing wrong. I have one problem and also, function doesn't work : Object reference not set to an instance of an object.
Public Function ConvertCtoL(ByVal ctol As String) As String
ctol = Replace(ctol, "Б", "B")
ctol = Replace(ctol, "б", "b")
**End Function** ' doesn't return a value on all code paths
Since I didn't found a solution for cyrillic to latin text I was planning to create function that would replace every letter from one alphabet to another.
You need Return ctol to tell it what value to return.
Perhaps researching "lookup table" would help you make a neater function.
Edit: The Wikipedia entry for Lookup table should be a good start.
Here is a simple example:
Imports System.Text
Module Module1
Function ReverseAlphabet(s As String) As String
Dim inputTable() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
Dim outputTable() As Char = "ZYXWVUTSRQPONMLKJIHGFEDBCA".ToCharArray()
Dim sb As New StringBuilder
For Each c As Char In s
Dim inputIndex = Array.IndexOf(inputTable, c)
If inputIndex >= 0 Then
' we found it - look up the value to convert it to.
Dim outputChar = outputTable(inputIndex)
sb.Append(outputChar)
Else
' we don't know what to do with it, so leave it as is.
sb.Append(c)
End If
Next
Return sb.ToString()
End Function
Sub Main()
Console.WriteLine(ReverseAlphabet("ABC4")) ' outputs "ZYX4"
Console.ReadLine()
End Sub
End Module