C# help to set a Row Css class of a Grid View - c#

I need to alternate row colors in a grid, but not on every other row. I have a variable _AddDate that I can check on the GridRowBound event. If it hasn't changed, I want to apply one css class and if it has I want to apply a different class. The code I have does almost exactly what I want but I am setting the class on the row when the value changes and each concurrent row that should be the same class is having the incorrect class applied. Its definitely something wrong with my method. Can anyone point me in the right direction? Also is there a name for these types of functions. I have to do things like this from time to time and they can be tricky to figure out the correct algorithm. Here is what I have.
private void GridRowBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.CssClass = SetRowColor();
}
}
private DateTime _dateToSwitch;
private string SetRowColor()
{
var tmpDate = _AddDate;
var doSwitch = (tmpDate == _dateToSwitch);
if (!doSwitch)
{
_dateToSwitch = tmpDate;
return "commentRow";
}
return "altCommentRow";
}
I have another function that correctly sets _AddDate to the appropriate value so it is always current when it is evaluated.
Any help is appreciated. Happy Friday!
Cheers,
~ck in San Diego

I can't think of a more elegant way of doing this (at the moment) aside from this:
private DateTime _previousRowDateTime;
private string[] _commentRowClasses = {"commentRow", "altCommentRow"};
private int _commentRowClassesIndex = 0;
private string SetRowColor()
{
if( _AddDate != _previousRowDateTime )
{
_commentRowClassesIndex = ( _commentRowClassesIndex + 1 ) % 2;
_previousRowDateTime = _AddDate;
}
return _commentRowClasses[_commentRowClassesIndex];
}

What your code is saying:
If the last date stored is NOT equal to the "_AddDate" variable
then SET it to that and return that this is a "commentRow".
If the last date stored IS equal to the "_AddDate" variable
then simply return "altCommentRow".
So, on 2 consecutive rows with the same date where _AddDate has NOT changed, the first one will get the "commentRow" style and the second one, will get "altCommentRow".
If your goal is to rotate coloring so that all consecutive rows with the same date are one color, then, when a new date is reached, switch to the next color, you could try something like this:
private bool _AltFlag;
private string _PreviousDate;
private string SetRowColor()
{
if (_AddDate != _PreviousDate)
{
_AltFlag = !_AltFlag;
}
return _AltFlag ? "altCommentRow" : "commentRow";
}
Essentially, we set up a bool to tell us which of the classes we're currently using. If our current date is not the same as the previous date, then flip the flag and return the new class. If it IS the same, we keep the same flag and return the class.

Related

Using array in if condition to know if the index is null in c#

I have declared my array like this,
string[] timeArrivalArray = new string[10];
Now, let's assume that on every click on the add button, something is inserting there.
However I want to use an if condition to a certain index.
I want to use something like this
if (timeArrivalArray[] == [2]) {
}
Now whenever I click the button, the timeArrivalArray[] will check if it's already in the 2nd index and then execute the code. tl;dr I just want to use the if condition to the 2nd index, how can this be?
EDIT:
My problem is it's throwing excemption in the first increment. I have a button and something inserting from some variables. However, the code above is inserted in this
if (timeArrivalArray[] == [2]) {
//*insert variable this*
} else {
// *insert variable that*
}
EDIT 2:
Yes it's not the correct syntax and I just know how to do it. But the root of my problem is this
DateTime theCalcu = DateTime.ParseExact(timeArrivalArray[2], "h:mm tt", System.Globalization.CultureInfo.InvariantCulture);
It's throwing me String reference not set to an instance of a String.
Maybe because he can't find any index to the preceding indexes.
Any suggestion would do.
As much as I could comprehend from your post here is the logic I can think of. You can let me know what doesn't work out of it.
string[] timeArrivalArray = new string[10];
public void Button1_Click(object sender, EventArgs e)
{
if (timeArrivalArray[2] == null)
{
//keep inserting into the array since 2nd index is null
}
else if (timeArrivalArray[2] != null && timeArrivalArray[2] == "someInputValue")
{
//2nd index is non null and some existing value found
//so do something else
}
else
{
//2nd index isn't null but input value wasn't found so keep inserting
}
}
whenever I click the button. The timeArrivalArray[] will check if it's already in the 2nd index[...] I just want to use the if condition to the 2nd index
This sounds to me like you want to count up the index every time a click occurs. If so you should specify an index variable outside of the scope of the click event:
string[] timeArrivalArray = new string[10];
int index = 0;
public void Button1_Click(object sender, EventArgs e)
{ // make sure you are not running out of bounds
if(index < timeArrivalArray.Length)
{
if(index == 2)
{
timeArrivalArray[index] = //*insert variable this*
}
else
{
// *insert variable that*
}
}
index ++; // walk to the next position
}

How to know if previous insert to textbox was equal to actual insert

Can you help me figure out, how to know if previous text inserted to the textbox, and actual insert is equal to each other?
For example if I insert "word 1" to text box, then enter it, and after I insert "word 2" in this case nothing happens, but if I insert "word 1" again after "word 1", I must know about it.
Comparison of recorded and inputed lines does not make sense in this case, because I do not always save string into the text file, but I want to know if string is same with actual insert and previous insert comparison, even if line does not exist in file.
I need value which exist between two actual and previous inserts and if previous insert is equal to actual insert, display this fact, annul value, but if actual insert is different remove this temporal value.
I'm not sure how to properly get this result for actual insert with textbox, how to know about equality for next and previous insert.
I'm sure my attempt is bad and probably wrong, and my question would be rated as bad, but anyway:
I'm trying to add actual string record to the list with 0 index, then if next actual value is equal to string in this list, make field variable value equal to 1 and clear list, otherwise clear list and annul field variable value. Then if field variable is not equal to zero display "Repeat of previous insert" and annul field variable value, clear temporal list.
But seems like comparison of actStr and list record rpt[0] it is not comparison of previous and actual, but just actual with actual, so it does not works proper, ans looks like absolutely wrong way to do it:
List<string> rpt = new List<string>();
string tempRptCheck = actStr;
rpt.Insert(0, tempRptCheck);
if (actStr == rpt[0])
{
rptVal = (rptVal = 1);
rpt.Clear();
}
else
{
rptVal = (rptVal = 0);
rpt.Clear();
}
if (rptVal > 0)
{
Console.WriteLine("Repeat of previous insert");
rptVal = (rptVal = 0);
rpt.Clear();
}
To be clearer again:
I want get notification in case if actual input is equal to previous input, for example:
Insert to textbox is a string "word1", then press enter to further process. So it must be recorded in the list, and if following insert is equal to this previous insert, with same "word1", notify me about this equality, remove this string form the list and change it to actual "word1", and if next insert will be same again, do the same.
But if insert is "word1", it must be recorded to this list, and if following insert is not equal to this previous insert, remove this string form the list and change it to actual "word2" to avoid such case if insert is "word1", and following insert is "word2" not equal to this previous, and then next following insert is "word1" again equal to before last, it should not be considered as repetition.
So I want get notification of repetition only between actual and prevous, or to put it differently actual and next inserts.
To be more clear, I want exactly this logic, which works with desired result only with console application:
static void Main(string[] args)
{
var words = new List<string>();
while (true)
{
Console.Write("Add word: ");
var input = Console.ReadLine();
if (words.Contains(input))
{
Console.WriteLine($"{input} is already in the list!");
continue;
}
words.Clear();
words.Add(input);
}
Console.ReadLine();
}
but It does not works with textbox, I got same result as with code above: each request as already exist. And while (true) loops in endless cycle, because same happens here, actual equals actual.
Also I've tried this way, to pass value about repeated text to field variable rpt but it does not works:
string OldText = string.Empty;
private void textBox1_GotFocus(object sender, EventArgs e)
{
OldText = textBox1.Text;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
string newText = textBox1.Text;
if (newText == OldText)
{
rpt = (rpt = 1);
}
else
{
rpt = (rpt = 0);
}
}
I have tried it with simple code. use _Leave event of textbox. Also, make sure to clear the list before entering new values.
Also, I have declared the List variable at class level:
List<string> a = new List<string>();
private void textBox1_Leave(object sender, EventArgs e)
{
if(a.Contains(textBox1.Text))
{
MessageBox.Show("Notify");
}
else
{
a.Clear();
a.Add(textBox1.Text);
}
}
You don't need a List, because you want compare only against last inserted value. Instance of string is enough.
For example if your form have three TextBoxes. You can use Leave eventhandler, because you want check against last inserted text only when user finish with current TextBox and moving to the another. TextChanged will be raised every time you add or remove character
public class MyForm : Form
{
private string _LastInsertedText;
public MyForm()
{
thisTextBox1.Leave += TextBox_Leave;
thisTextBox2.Leave += TextBox_Leave;
thisTextBox3.Leave += TextBox_Leave;
}
private void TextBox_Leave(object sender, EventArgs e)
{
var textBox = (TextBox)sender;
if(textbox.Text.Equals(_LastInsertedText))
{
// notify about same value
}
else
{
_LastInsertedText = textbox.Text
}
}
}
It will notify only when you move focus to another control
If you want notify about equality only if inserted value is same as previously inserted in this TextBox, then use TextBox.Tag property
private void TextBox_Leave(object sender, EventArgs e)
{
var textBox = (TextBox)sender;
var previousText = (string)textbox.Tag;
if(textbox.Text.Equals(previousText))
{
// notify about same value
}
else
{
textbox.Tag = textbox.Text
}
}

Example use of TimeSpan.MinValue? Why would anyone use that in practice?

I was using TimeSpans and found about TimeSpan.MinValue in MSDN. I was wondering why they include that directly in the class, or better yet: if there was a classic example of why/when you would want to use it. Of course it's good to know the value, but one can look that up.
I thought of stuff like subtracting other TimeSpans but it doesn't really make sense to me.
Any ideas? Thanks!!
One thing that comes to mind:
static TimeSpan FindMax(params TimeSpan[] intervals) {
if (intervals.Length == 0)
throw new ArgumentException("intervals collection is empty");
var max = TimeSpan.MinValue;
foreach (var interval in intervals) {
if (interval > max)
max = interval;
}
return max;
}
TimeSpan is a struct, not a class. This means it cannot have a null value (without wrapping it in a System.Nullable). Therefore, what value should it be given if you instantiate a variable as a TimeSpan?
The designer has opted for the minimum value possible, but rather than encode this as a magic value, they have exposed it as the TimeSpan.MinValue constant.
One example I can give you is where it could be used as an alternative to a Nullable TimeSpan property in a class (TimeSpan is Nullable, by the way)
And you're displaying some text somewhere - that relies on something being "set" (or not).
Let's say a string that is showing how long something has been running.
Use a full property (with backing field) to achieve this:
Set the initial field's value to TimeSpan.MinValue which you can then use a public property to alter. Then, for the string you want to display, use your favourite PropertyChanged event handler (or other code) to update your view:
private TimeSpan _lengthOfTime = TimeSpan.MinValue;
public TimeSpan LengthOfTime
{
get { return _lengthOfTime; }
set
{
_lengthOfTime = value;
OnPropertyChanged("LengthOfTimeString");
}
}
public string LengthOfTimeString
{
get
{
if (LengthOfTime == TimeSpan.MinValue)
{
return "The length of time has not been set.";
}
else
{
return LengthOfTime.ToString("YourFavouriteStringFormatHere");
}
}
}
When you then update your LengthOfTime property, it will call OnPropertyChanged (or whatever you use to update the UI) to get the LengthOfTimeString value, which is then re-calculated and displayed on your view.
This is only an example; and your scenario of what to use it for might be different.
I would suggest looking at https://msdn.microsoft.com/en-us/library/ms229614(v=vs.100).aspx, which tells you about how to implement INotifyPropertyChanged; if you're thinking of using Bindings in WPF/XAML/WinRT (if you don't know how to already).

Axosoft Report Builder (Active Reports 3) - Conditional Results Depending on Field Value

I am trying to create a custom report using Axosoft's Report Builder though I have one big issue to tackle. The report will contain calculated totals and counts of the specific items that are pulled in from the database to display. One such field (Custom_163) is a boolean where true will have it be one type of item (Enhancement) while false will have it as another (Maintenance). I am able to get a count of the total amount of items in the report, but I want to break it down as percentages of the total.
Problem: One boolean field will determine two types of items. Differentiating between them to gather a count of each is where I'm struggling.
Initialized Variables:
private bool _oddRow = true;
private string[] _labels = new string[3];
private int _defectsTotal = 0;
private int _enhanceTotal = 0;
private int _maintenTotal = 0;
Detail Section (where it's creating the rows for the items):
public void Detail1_Format()
{
if (rpt.Fields.Contains("Custom_163") && rpt.Fields["Custom_163"].Value != null)
{
if ((bool)rpt.Fields["Custom_163"].Value == true)
{
//needs something here to add a count towards this type
return enhanceTotal;
}
else
{
//needs something here to add a count towards this type
return maintenTotal;
}
_defectsTotal++;
_enhanceTotal += enhanceTotal;
_maintenTotal += maintenTotal;
// To Color Every Other Row
if (_oddRow)
{
rpt.Sections["Detail1"].BackColor = System.Drawing.Color.FromArgb(224, 224, 224);
}
else
{
rpt.Sections["Detail1"].BackColor = System.Drawing.Color.White;
}
_oddRow = !_oddRow;
// Converting to String Values
if (rpt.Fields["ItemId"].Value == null) return;
}
}
The problem is specifically with these lines:
if((bool)rpt.Fields["Custom_163"].Value == true)
I've changed this a ton from similar conditions:
if(rpt.Fields["Custom_163"].Value.ToString() == "True")
if(rpt.Fields["Custom_163"].Value == true)
if(rpt.Fields["Custom_163"].Value = true)
if(rpt.Fields["Custom_163"].Value == 1)
if(rpt.Fields["Custom_163"].Value.ToString() == "1")
if (Convert.ToBoolean(rpt.Fields["Custom_163"].Value) == true)
etc...
But they don't seem to work as intended. I want it to filter out the items where this field is true so the rest will execute.
Another thing is returning the values from the if-else statement (not working and I've tried using a separate method below that doesn't work either):
public class findTotals
{
public findTotals()
{
}
public int resultTotals()
{
bool item = (bool)rpt.Fields["Custom_163"].Value;
if ( item == true)
{
int enhanceTotal = 1;
return;
}
else
{
int maintenTotal = 1;
return;
}
}
}
(This whole method needs a ton of work TBH).
Lastly, these lines has to be outside of the second if-else or at least somehow returned to the original if in order to be printed to the report:
_enhanceTotal += enhanceTotal;
_maintenTotal += maintenTotal;
The _defectsTotal gets a total count of all the items and that works fine. These two lines though are supposed to add a count based on the above conditions for each type so then the total amount of Enhancements and total amount of Maintenance Items get posted at the end of the report. It doesn't work, if not a casting/conversion error or the conditions force the array(s) out of bounds, it's some other issue. I've played around the order for all these too.
Possible Solutions?
How to safely convert (if needed) the bool values to int so that number can be used to add to a total?
How can I return the values in the if-else so the scope matches up with the variables? Will I need a method?
Thank you in advance.
You should be able to do a string compare against "True". i.e.
if(string.Compare(rpt.Fields["Custom_163"].Value.ToString(), "True") == 0)
I figured out what the issue was.
So basically...
if (Convert.ToBoolean(rpt.Fields["Custom_163"].Value) == true)
{
enhanceTotal++;
}
else
{
maintenTotal++;
}
_defectsTotal++;
(This is all within another if-statement and a bunch of code not relevant to issue.) This works fine and actually returns the count, after that another hurdle was figuring out the labels so it can print into it's placeholders correctly. The whole findTotals method wasn't needed. I didn't need any more variables than the three listed above to make it work. A reason I kept on getting errors was because I tried to use one variable as a label to print into different places within the report which isn't allowed apparently. Instead of using one label and sticking it everywhere, I made several that were identical and made sure to give them different names, etc.
So instead of X in three different report sections, X was X, Y, Z (all identical but different identifer) and stuck it where needed. Man, it seems to obvious now, well thanks again.

Convert one type into another

I have a problem with convertion types. My mainForm keeps variable in integer type. Also my form has propertyGrid where I realized property for field (like combobox) with Image & Text. And now I don't understand well how can I convert one type into another. First I need to convert data from int to myProp and then vice versa.
Here setup propertyGrid:
public dashPatternList DashPattern
{
get { return dashPattern; }
set { dashPattern = value; }
}
Here I tried to realize my problem with additional methods:
private dashPatternList dashIN(int dash)
{
dashPatternList ds = dashPatternList.pic0;
if (dash == 1) ds = dashPatternList.pic1;
if (dash == 2) ds = dashPatternList.pic2;
return ds;
}
private int dashOUT(dashPatternList dash)
{
int i = 0;
if (dash == dashPatternList.pic1) i = 1;
if (dash == dashPatternList.pic2) i = 2;
return i;
}
And call it:
pData.DashPattern = dashIN(dashPattern);
dashPattern = dashOUT(pData.DashPattern);
This method works, but maybe you suggest me more easy way.
You could keep the pictures in an array, so instead of dashIN(dash) you'd write dashIN[dash] (and you don't need to write the dashIN function). You just need to initialize it once with something like this:
DashPattern[] dashIN = new DashPattern[] {
dashPatternList.pic0, dashPatternList.pic1, dashPatternList.pic2 };
For the reverse, something like Array.IndexOf(dashIN,mypic) should work.
This way you replace code with data, which tends to be a good thing as it's usually easier to manage. For example now you only have to change one line if you want to change the list of dash patterns, instead of having to change the code in two functions earlier. Plus now it's impossible to make an error that would cause dashOUT(dashIN(dash))!=dash (as would happen if there's a wrong number in the code).

Categories