ReDim a Dynamic-Dimension Array - arrays

So, I'm not really sure how to even title this kind of question. I've tried searching for an answer, but maybe I'm not using the right term(s). Here's the basic idea:
I have a form that contains a TreeView on the left side acting as an "Options" form. Based on the node selected in the TreeView, the appropriate Panel is displayed on the right with the controls for the selected setting. Since I'm only in the beginning of designing this form, I'm not sure how many options I'll have in the end; and thus, I'm not sure how many Panels I will have in the end.
Options Screen
Initially, the problem has been solved by placing all of the Panels inside a single parent Panel and creating a loop (or 4) to add all Control.Panel objects to a Control Array. This allows me to display the correct Panel based on the selected node, dynamically. The problem is...I currently only have a single sub-level (i.e. Parent and Parent-Child nodes), thus my array only needs to be 2-Dimensional. But should I decide to add another level (i.e. Parent-Child-Child), my array would need to be 3-Dimensional.
Imports System.ComponentModel
Imports System.Text.RegularExpressions
Public Class frm_options
Dim all_controls(,) As Control = {} 'Array of panel controls inside of panel_container.
Private Sub frm_options_Load(sender As Object, e As EventArgs) Handles Me.Load
'Fill (and resize as needed) the all_controls(,) array with the panel controls based on their x,y coordinates by name.
'Arrange ALL panels to the correct location.
Dim x As Integer = 0
Dim y As Integer = 0
For Each panel_control As Control In panel_container.Controls
If TypeOf (panel_control) Is Panel Then
'Find the total amount of x,y panels that we need to fit into our array.
'Find x,y dimension that panel should fit into array based on name [i.e. panel_1_0(0,0), panel_1_1(0,1), panel_2_0(1,0), panel_2_1(1,1), etc.]
Dim xy As MatchCollection = Regex.Matches(panel_control.Name, "panel_(\d)*_*(\d)")
For Each m As Match In xy
For Each cx As Capture In m.Groups(1).Captures
'For every x
If (cx.Value > x) Then
x = cx.Value
End If
For Each cy As Capture In m.Groups(2).Captures
'For every y in x
If (cy.Value > y) Then
y = cy.Value
End If
'Because we start our panel naming convention at 1_0, we must subtract this from our X value but not Y.
ReDim Preserve all_controls(x - 1, y)
all_controls(cx.Value - 1, cy.Value) = panel_control
Next
Next
Next
End If
Next
'At this point, x = maximum x coordinates needed, y = maximum y coordinates needed and all_controls contains a list of Panels for the TreeView.
End Sub
Private Sub options_tree_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles options_tree.AfterSelect
'All below examples assume there is a single parent and child node.
'If there is a need for a child in a child node, change Level to > 1 (or however many childs needed)
If (options_tree.SelectedNode.Level > 0) Then
'If the selected node is a child node...
For Each control_panel In all_controls
If (control_panel IsNot Nothing) Then
If (control_panel Is all_controls(options_tree.SelectedNode.Parent.Index, options_tree.SelectedNode.Index + 1)) Then
control_panel.Visible = True
Else
control_panel.Visible = False
End If
End If
Next
Else
'If the selected node is a parent node...
For Each control_panel As Control In all_controls
If (control_panel IsNot Nothing) Then
If (control_panel Is all_controls(options_tree.SelectedNode.Index, 0)) Then
control_panel.Visible = True
Else
control_panel.Visible = False
End If
End If
Next
End If
End Sub
Forgive my ugly coding...I'm sure there are much easier ways to achieve this - but I only code as a hobby and have never taken any courses on it. As you can see, this code allows me to add as many nodes and respective panels as needed (as long as I continue to use the right naming convention) without having to change any of my code to implement the new controls. But should I add another level to the TreeView, I will need to modify the code to use a 3-Dimensional array instead.
So in short, I'm sure there is a completely different method I should be using. If so, what would it be? Again, I want to have a code that allows me to add nodes, levels, and panels to my form without having to change the code to control these elements.
Edit: Through my research, I've looked into the Collection class. My problem with using this is that I don't think I would be able to reference which panel to display based on the Index of the selected node.

Related

Why does my Clear TexBox command makes the rest of my number in the listbox zero?

Every number is zero.
Hi, I’m fairly new to VisualStudio and I have this problem in my code:
What I have to do, is to fill an array (all the variables have to be local!) of three numbers and display the numbers in a listbox, when the array is full disable the button to add numbers and at the end display another array in other listbox but with the values divided by two (that’s another story tho).
It worked at first and I could add the numbers fine, but, I had to clear the textbox manually every time I wanted to add a number, so I tried to add the command
Me.txtAddNumber.Clear()
but after that every time I added a number, it appeared in the listbox as 0. What can I do to fix it?
My code right now is:
Private Sub btnAddToArray_Click(sender As Object e As EventArgs)Handles btnAddToArray.Click
Dim ArrayListOriginal(2) As Integer
Static Index As Integer = 0
Me.txtAddNumber.Clear()
ArrayListOriginal(Index) = Val(Me.txtNumToInput.Text)
lstOriginal.Items.Add(ArrayListOriginal(Index))
If
Index = ArrayListOriginal.Lenght Then Me.btnToAddArray.Enabled = False
End If
End Sub
Thanks for your help!

UDF that fetches array data is not getting up to date data when the array is changed from Worksheet Change Event

I have a variable number of cells (~500 to 10,000+) whose values need to be retrieved as they are changed. I have a WorkSheet_Change event that captures changes to these cells and makes updates to an array. Further calculation and updates occur within the array structure to come up the result(s).
I had originally done this with multiple hidden sheets, but the performance was terrible. With the memory based arrays, everything works fast and fine up to this point.
I have a bunch of cells that represents the sum of parts of the dependent range(s) that could change. If the value within these cells changes, I know the dependent cells have changed and the latest calculations should be ready to fetched from the array.
The problem is that the function is fetching data from the array before the Change event has updated the array, and hence you see the 'previous' value.
A simplified simulation of the problem:
In a Module:
Option Explicit
Public tData(1 To 1, 1 To 1) As Double
Public Function GetArrayData(CelltoCheckForChanges) As Double
If IsEmpty(tData) Then tData(1, 1) = 0
GetArrayData = tData(1, 1)
End Function
In the Worksheet code:
Private Sub Worksheet_Change(ByVal Target As Range)
If (Not Application.Intersect(Target, Range("D3")) Is Nothing) Then
tData(1, 1) = Target.Value
End If
End Sub
In the sheet, set cell B3 to be "=GetArrayData(D3)" and then enter numbers in to cell D3. The numbers in B3 will reflect the 'previous' value. FYI, the "CelltoCheckForChanges" in the GetArrayData is the reference to cell that flags if there has been a change in any of the dependent cells to trigger a fetch from the array (the dependent cells are not shown for simplicity).
I have tried placing disabling/enabling events as well as manual vs auto calcs around the change event with no impact. (FYI, trying to avoid switching calc on/off if it all possible).
Hope someone can provide some insight, fixes or ideas for alternative approaches on this.

How to create an array with textboxes in Visual Basic 6.0

I am working on a very old visual basic project. I have to rewrite the load and save function of the project. Therefore I wanted to create an array of controls which have all relevant textboxes and checkboxes included. I want to iterate through that array to be able to save the data into a textfile or load from it.
I have looked on the internet of how you can define those arrays, but it doesn't seem to work for me. Maybe I am doing something wrong, cause I am not an expert in Visual Basic.
I have tried to make it work this way:
Dim tbList As TextBox = { Form1.Text1, Form1.Text3, _
Form1.Text10, Form1.Text11, Form1.Text12, Form1.Text13, _
Form2.Text1, Form2.Text3, Form2.Text4, Form2.Text5, _
Form2.Text10, Form2.Text11, Form2.Text12, Form2.Text13, _
Form3.Text1, Form3.Text3, Form3.Text4, Form3.Text5, _
Form3.Text10, Form3.Text11, Form3.Text12, Form3.Text13, _
Form3.Text17, Form3.Text18, Form3.Text19, Form3.Text20, _
Form4.Text1, _
Form5.Text1, Form5.Text2, Form5.Text3, _
Form6.Text2, _
Form7.Text2}
Or with a list:
Dim tbList As New List(Of Controls)
The thing is Visual Basic always tells me there are some kind of compiling issues. There is no real explantation for this issue in VB, so I am asking here.
Your code isn't compiling because it is vb.net code. It should go without saying (but I'll say it anyway) that vb6 and vb.net are not the same thing.
If you want to use an array, you will have to dimension the array with a number that is one less than your number of textboxes (if I counted correctly there are 32 in your example):
'// array is zero based so 0 to 31 = 32 items
Dim tbList(31) As TextBox
tbList(0) = Form1.Text1
tbList(1) = Form1.Text3
'//...I'll leave the rest as an exercise for the programmer
tbList(31) = Form7.Text2
Dim i As Integer
Dim tb As TextBox
'// To loop and work with each textbox
For i = 0 To UBound(tbList)
Set tb = tbList(i)
'// do something with tb
Next
An easier way to do it, however, is to work with a collection:
Dim tbList As New Collection
tbList.Add Form1.Text1
tbList.Add Form1.Text3
'//...I'll leave the rest as an exercise for the programmer
tbList.Add Form7.Text2
Dim tb As TextBox
'// To loop and work with each textbox
For Each tb In tbList
'// do something with tb
Next
Yes, you can use a collection if you want to go to the trouble. But an even easier way to work with it is to use VB6's (now obsolete) control array implementation. Most of us were disappointed when we found it was no longer available in .Net!
All you have to do to get control arrays in VB6 is create a bunch of controls with the same name. (They do have to be the same type of control; you can't make arrays of, say, text boxes and combo boxes.) Start with one text box, name it what you want, and copy it. You will be asked if you want to create a control array. Say yes, copy as many as you want. You will notice that the Index property is no longer blank, starting with 0 and incrementing from there. You will also notice that all of the event handlers have an "Index As Integer" argument to them. This way, you can use the same event handler for all of them, evaluating the Index argument to find out which member of your array is firing the event.
Here is the old doc for it. Microsoft makes it hard to find. :)

VBA Excel - Returning an array of ListBoxes from a function

I am currently working on a module that is meant to populate three ActiveX ListBoxes. Each will be populated with the same values: choices for axes titles on a graph (X-axis, Primary Y-Axis and Secondary Y-Axis). I have a function called "FillBox" that takes a ListBox as an argument and populates it.
Originally I used the following to accomplish this:
Sub FillAllBoxes()
FillBox X_BOX
FillBox Y1_BOX
FillBox Y2_BOX
End Sub
I was informed that I cannot use a Union to compact this code because of the MSForms.ListBox object type. There are many other subs that perform a repeated operation on each box, so it appears that some sort of array would be best to use.
So far, the only way I have found to define this array of ListBoxes is the following, though I am unsatisfied with the fact that the return value is a Variant but I can't seem to get it to work if I define it as Function BOX_ARRAY() As MSForms.ListBox:
Function BOX_ARRAY() As Variant
Dim Temp(1 To 3) As MSForms.ListBox
Set Temp(1) = X_BOX
Set Temp(2) = Y1_BOX
Set Temp(3) = Y2_BOX
BOX_ARRAY = THIS_ARRAY
End Function
I can then use this sub, though I needed to explicitly define the argument to FillBox as ByVal, because BOX_ARRAY is a variant.
Sub FillAllBoxes()
For j = LBound(BOX_ARRAY) To UBound(BOX_ARRAY)
FillBox BOX_ARRAY(j)
Next j
End Sub
A) Is there any way to have a function return an array that is not a Variant?
B) Would it be wise to stick with my original method of just repeating the function explicitly for each list box or is it worth using arrays for this type of operation?
C) In the function BOX_ARRAY is there a way around defining a Temp array and just populating the returned array right off the bat?
Here goes:
There are many other subs that perform a repeated operation on each box
Simply pass the ListBox to a function that operates on listboxes, e.g.:
Sub MyExample()
EnableListBoxes Array(Me.ListBox1, Me.ListBox2, Me.ListBox3)
End Sub
Sub EnableListBoxes(boxes as Variant)
Dim lbox as variant
For each lbox in boxes
lbox.Enabled = True
Next
End Sub
Alternatively you can pass the entire form/worksheet/whatever contains the listboxes, and iterate over the collection containing them (e.g., UserForm.Controls, etc.) You'd need to do some additional logic to make sure you're operating on the right type of form control, but that is relatively easy to do.
I can't seem to get it to work if I define it as Function BOX_ARRAY() As MSForms.ListBox
Of course not, because an MSForms.ListBox is a single object. You can't expect to return an array of anything in to a function that is designed to return an object.
Is there any way to have a function return an array that is not a Variant?
Perhaps use a subroutine and pass the arguments ByRef. You don't need to return a value if you are operating on the reference directly, rather than a local copy of it. See Chip Pearson for some detailed explanations/examples:
http://www.cpearson.com/excel/passingandreturningarrays.htm
Sub TestByRef()
Dim i as Integer
i = 1
ChangeValue i
Debug.Print i
End Sub
Sub ChangeValue(ByRef x as Integer)
x = 3
End Sub
In the function BOX_ARRAY is there a way around defining a Temp array and just populating the returned array right off the bat?
Not that I can think of. Perhaps with a class module and the class _Initialize method, you could automatically assign one of the class properties. But I think that ultimately is the same method: creating a temporary array that defines the return value. It is hard to tell for sure since you don't provide enough code (e.g., where are the variables? are they even declared?

Add alternating row color to SQL Server Reporting services report

How do you shade alternating rows in a SQL Server Reporting Services report?
Edit: There are a bunch of good answers listed below--from quick and simple to complex and comprehensive. Alas, I can choose only one...
Go to the table row's BackgroundColor property and choose "Expression..."
Use this expression:
= IIf(RowNumber(Nothing) Mod 2 = 0, "Silver", "Transparent")
This trick can be applied to many areas of the report.
And in .NET 3.5+ You could use:
= If(RowNumber(Nothing) Mod 2 = 0, "Silver", "Transparent")
Not looking for rep--I just researched this question myself and thought I'd share.
Using IIF(RowNumber...) can lead to some issues when rows are being grouped and another alternative is to use a simple VBScript function to determine the color.
It's a little more effort but when the basic solution does not suffice, it's a nice alternative.
Basically, you add code to the Report as follows:
Private bOddRow As Boolean
'*************************************************************************
' -- Display green-bar type color banding in detail rows
' -- Call from BackGroundColor property of all detail row textboxes
' -- Set Toggle True for first item, False for others.
'*************************************************************************
Function AlternateColor(ByVal OddColor As String, _
ByVal EvenColor As String, ByVal Toggle As Boolean) As String
If Toggle Then bOddRow = Not bOddRow
If bOddRow Then
Return OddColor
Else
Return EvenColor
End If
End Function
Then on each cell, set the BackgroundColor as follows:
=Code.AlternateColor("AliceBlue", "White", True)
Further Reading: Report Solution Patterns and Recipes: Greenbar Reports | Wrox
I got the chess effect when I used Catch22's solution, I think because my matrix has more than one column in design.
that expression worked fine for me :
=iif(RunningValue(Fields![rowgroupfield].Value.ToString,CountDistinct,Nothing) Mod 2,"Gainsboro", "White")
I have changed #Catch22's solution A bit as I do not like the idea of having to go into each field if I decide I want to change one of the colors. This is especially important in reports where the are numerous fields that would need to have the color variable changed.
'*************************************************************************
' -- Display alternate color banding (defined below) in detail rows
' -- Call from BackgroundColor property of all detail row textboxes
'*************************************************************************
Function AlternateColor(Byval rowNumber as integer) As String
Dim OddColor As String = "Green"
Dim EvenColor As String = "White"
If rowNumber mod 2 = 0 then
Return EvenColor
Else
Return OddColor
End If
End Function
Noticed that I have change the function from one that accepts the colors to one that contains the colors to be used.
Then in each field add:
=Code.AlternateColor(rownumber(nothing))
This is much more robust than manually changing the color in each fields' background color.
One thing I noticed is that neither of the top two methods have any notion of what color the first row should be in a group; the group will just start with the opposite color from the last line of the previous group. I wanted my groups to always start with the same color...the first row of each group should always be white, and the next row colored.
The basic concept was to reset the toggle when each group starts, so I added a bit of code:
Private bOddRow As Boolean
'*************************************************************************
' -- Display green-bar type color banding in detail rows
' -- Call from BackGroundColor property of all detail row textboxes
' -- Set Toggle True for first item, False for others.
'*************************************************************************
Function AlternateColor(ByVal OddColor As String, _
ByVal EvenColor As String, ByVal Toggle As Boolean) As String
If Toggle Then bOddRow = Not bOddRow
If bOddRow Then
Return OddColor
Else
Return EvenColor
End If
End Function
'
Function RestartColor(ByVal OddColor As String) As String
bOddRow = True
Return OddColor
End Function
So I have three different kinds of cell backgrounds now:
First column of data row has =Code.AlternateColor("AliceBlue", "White", True) (This is the same as the previous answer.)
Remaining columns of data row have =Code.AlternateColor("AliceBlue", "White", False) (This, also, is the same as the previous answer.)
First column of grouping row has =Code.RestartColor("AliceBlue") (This is new.)
Remaining columns of grouping row have =Code.AlternateColor("AliceBlue", "White", False) (This was used before, but no mention of it for grouping row.)
This works for me. If you want the grouping row to be non-colored, or a different color, it should be fairly obvious from this how to change it around.
Please feel free to add comments about what could be done to improve this code: I'm brand new to both SSRS and VB, so I strongly suspect that there's plenty of room for improvement, but the basic idea seems sound (and it was useful for me) so I wanted to throw it out here.
for group headers/footers:
=iif(RunningValue(*group on field*,CountDistinct,"*parent group name*") Mod 2,"White","AliceBlue")
You can also use this to “reset” the row color count within each group. I wanted the first detail row in each sub group to start with White and this solution (when used on the detail row) allowed that to happen:
=IIF(RunningValue(Fields![Name].Value, CountDistinct, "NameOfPartnetGroup") Mod 2, "White", "Wheat")
See: http://msdn.microsoft.com/en-us/library/ms159136(v=sql.100).aspx
Michael Haren's solution works fine for me. However i got a warning saying that "Transparent" is not a valid BackgroundColor when Preview. Found a quick fix from
Setting BackgroundColor of Report elements in SSRS. Use Nothing instead of "Transparent"
= IIf(RowNumber(Nothing) Mod 2 = 0, "Silver", Nothing)
The only effective way to solve this without using VB is to "store" the row grouping modulo value within the row grouping (and outside the column grouping) and reference it explicitly within your column grouping. I found this solution at
http://ankeet1.blogspot.com/2009/02/alternating-row-background-color-for.html
But Ankeet doesn't the best job of explaining what's happening, and his solution recommends the unnecessary step of creating a grouping on a constant value, so here's my step-by-step process for a matrix with a single row group RowGroup1:
Create a new column within the RowGroup1. Rename the textbox for this to something like RowGroupColor.
Set the Value of RowGroupColor's textbox to
=iif(RunningValue(Fields![RowGroupField].Value
,CountDistinct,Nothing) Mod 2, "LightSteelBlue", "White")
Set the BackgroundColor property of all your row cells to
"=ReportItems!RowGroupColor.Value"
Set the width of the the RowGroupColor column to 0pt and set CanGrow
to false to hide it from clients.
Voila! This also solves a lot of the problems mentioned in this thread:
Automatic resets for subgroups: Just add a new column for that
rowgroup, performing a RunningValue on its group values.
No need to worry about True/False toggles.
Colors only held in one place for easy modification.
Can be used interchangeably on row or column groups (just set height to 0 instead of width)
It would be awesome if SSRS would expose properties besides Value on Textboxes. You could just stuff this sort of calculation in a BackgroundColor property of the row group textboxes and then reference it as ReportItems!RowGroup.BackgroundColor in all of the other cells.
Ahh well, we can dream ...
My problem was that I wanted all the columns in a row to have the same background. I grouped both by row and by column, and with the top two solutions here I got all the rows in column 1 with a colored background, all the rows in column 2 with a white background, all the rows in column 3 with a colored background, and so on. It's as if RowNumber and bOddRow (of Catch22's solution) pay attention to my column group instead of ignoring that and only alternating with a new row.
What I wanted is for all the columns in row 1 to have a white background, then all the columns in row 2 to have a colored background, then all the columns in row 3 to have a white background, and so on. I got this effect by using the selected answer but instead of passing Nothing to RowNumber, I passed the name of my column group, e.g.
=IIf(RowNumber("MyColumnGroupName") Mod 2 = 0, "AliceBlue", "Transparent")
Thought this might be useful to someone else.
I think this trick is not discussed here. So here it is,
In any type of complex matrix, when you want alternate cell colors, either row wise or column wise,
the working solution is,
If you want a alternate color of cells coloumn wise then,
At the bottom right corner of a report design view, in "Column
Groups", create a fake parent group on 1 (using expression), named
"FakeParentGroup".
Then, in the report design, for cells that to be colored
alternatively, use following background color expression
=IIF(RunningValue( Fields![ColumnGroupField].Value, countDistinct, "FakeParentGroup" ) MOD 2, "White", "LightGrey")
Thats all.
Same for the alternate color row wise, just you have to edit solution accordingly.
NOTE: Here, sometimes you need to set border of cells accordingly, usually it vanishes.
Also dont forget to delete value 1 in report that came into pic when you created fake parent group.
If for the entire report you need an alternating color, you can use the DataSet your Tablix is bound to for a report-wide identity rownumber on the report and use that in the RowNumber function...
=IIf(RowNumber("DataSet1") Mod 2 = 1, "White","Blue")
#Aditya's answer is great, but there are instances where formatting will be thrown off if the very first cell of the row (for row background formatting) has a missing value (in complex tablixes with column/rows groups and missing values).
#Aditya's solution cleverly leverages countDistinct result of runningValue function to identify row numbers within a tablix (row) group. If you have tablix rows with missing value in the first cell, runningValue will not increment countDistinct result and it will return the previous row's number (and, therefore, will affect the formatting of that cell). To account for that, you will have to add an additional term to offset the countDistinct value. My take was to check the first running value in the row group itself (see line 3 of the snippet below):
=iif(
(RunningValue(Fields![RowGroupField].Value, countDistinct, "FakeOrRealImmediateParentGroup")
+ iif(IsNothing(RunningValue(Fields![RowGroupField].Value, First, "GroupForRowGroupField")), 1, 0)
) mod 2, "White", "LightGrey")
Hope this helps.
Could someone explain the logic behind turning rest of the fields to false in below code (from above post)
One thing I noticed is that neither of the top two methods have any notion of what color the first row should be in a group; the group will just start with the opposite color from the last line of the previous group. I wanted my groups to always start with the same color...the first row of each group should always be white, and the next row colored.
The basic concept was to reset the toggle when each group starts, so I added a bit of code:
Private bOddRow As Boolean
'*************************************************************************
'-- Display green-bar type color banding in detail rows
'-- Call from BackGroundColor property of all detail row textboxes
'-- Set Toggle True for first item, False for others.
'*************************************************************************
'
Function AlternateColor(ByVal OddColor As String, _
ByVal EvenColor As String, ByVal Toggle As Boolean) As String
If Toggle Then bOddRow = Not bOddRow
If bOddRow Then
Return OddColor
Else
Return EvenColor
End If
End Function
'
Function RestartColor(ByVal OddColor As String) As String
bOddRow = True
Return OddColor
End Function
So I have three different kinds of cell backgrounds now:
First column of data row has =Code.AlternateColor("AliceBlue", "White", True) (This is the same as the previous answer.)
Remaining columns of data row have =Code.AlternateColor("AliceBlue", "White", False) (This, also, is the same as the previous answer.)
First column of grouping row has =Code.RestartColor("AliceBlue") (This is new.)
Remaining columns of grouping row have =Code.AlternateColor("AliceBlue", "White", False) (This was used before, but no mention of it for grouping row.)
This works for me. If you want the grouping row to be non-colored, or a different color, it should be fairly obvious from this how to change it around.
Please feel free to add comments about what could be done to improve this code: I'm brand new to both SSRS and VB, so I strongly suspect that there's plenty of room for improvement, but the basic idea seems sound (and it was useful for me) so I wanted to throw it out here.
I tried all these solutions on a Grouped Tablix with row spaces and none worked across the entire report. The result was duplicate colored rows and other solutions resulted in alternating columns!
Here is the function I wrote that worked for me using a Column Count:
Private bOddRow As Boolean
Private cellCount as Integer
Function AlternateColorByColumnCount(ByVal OddColor As String, ByVal EvenColor As String, ByVal ColCount As Integer) As String
if cellCount = ColCount Then
bOddRow = Not bOddRow
cellCount = 0
End if
cellCount = cellCount + 1
if bOddRow Then
Return OddColor
Else
Return EvenColor
End If
End Function
For a 7 Column Tablix I use this expression for Row (of Cells) Backcolour:
=Code.AlternateColorByColumnCount("LightGrey","White", 7)
Just because none of the answers above seemed to work in my matrix, I'm posting this here:
http://reportingservicestnt.blogspot.com/2011/09/alternate-colors-in-matrixpivot-table.html
My matrix data had missing values in it, so I wasn't able to get ahmad's solution to work, but this solution worked for me
Basic idea is to create a child group and field on your innermost group containing the color. Then set the color for each cell in the row based on that field's value.
Slight modification of other answers from here that worked for me. My group has two values to group on, so I was able to just put them both in the first arg with a + to get it to alternate correctly
= Iif ( RunningValue (Fields!description.Value + Fields!name.Value, CountDistinct, Nothing) Mod 2 = 0,"#e6eed5", "Transparent")
When using row and column groups both, I had an issue where the colors would alternate between the columns even though it was the same row. I resolved this by using a global variable that alternates only when the row changes:
Public Dim BGColor As String = "#ffffff"
Function AlternateColor() As String
If BGColor = "#cccccc" Then
BGColor = "#ffffff"
Return "#cccccc"
Else
BGColor = "#cccccc"
Return "#ffffff"
End If
End Function
Now, in the first column of the row you want to alternate, set the color expression to:
=Code.AlternateColor()
-
In the remaining columns, set them all to:
=Code.BGColor
This should make the colors alternate only after the first column is drawn.
This may (unverifiably) improve performance, too, since it does not need to do a math computation for each column.

Resources