i have a form with more than one NumericUpDown as controls to input answer. i want every input is true for an operation (multiplication, sum etc), NumericUpDown for that operation will be disable. i have used the code below (just for sum operation), but i think its not efficient because i have to make a method to check every operation.
private void IsSumTrue() {
if (add1 + add2 == sum.Value)
{
sum.Enabled = false;
}
}
private void IsDifferenceTrue()
{
if (add1 - add2 == difference.Value)
{
difference.Enabled = false;
}
}
private void IsProductTrue()
{
if (add1 * add2 == product.Value)
{
product.Enabled = false;
}
}
private void IsQuotientTrue()
{
if (add1 / add2 == quotient.Value)
{
quotient.Enabled = false;
}
}
anyone have idea how to make it more efficient with just a method for all operation?
below is my idea, but to check the value is true for every NumericUpDown i don't know how.
private void DisableIfValueIsTrue()
{
foreach(Control control in this.Controls)
{
NumericUpDown value = control as NumericUpDown;
// if(value [NEED HELP]
}
}
Considering your situtaion, you can set a tag for each NumericUpDown in design mode like this:
sum.Tag=1;
square.Tag=2;
etc
Then define some int variables:
int iSum=add1+add2;
int iSquare= //Whatever you want
etc
And finally loop through your controls this way:
foreach (NumericUpDown control in this.Controls.OfType<NumericUpDown>())
{
int intCondition = Convert.ToInt32(control.Tag) == 1
? iSum
: Convert.ToInt32(control.Tag) == 2
? iSquare
: Convert.ToInt32(control.Tag) == 3
? i3
: i4; //You should extend this for your 8 controls
control.Enabled = intCondition == control.Value;
}
OK! Second way I offer
Since you will have to always check 8 different conditions, you could simply forget about looping through the controls and just change your method like this:
private void DisableIfValueIsTrue()
{
sum.Enabled = add1 + add2 != sum.Value;
difference.Enabled= add1 - add2 != difference.Value;
product.Enabled= add1 * add2 != product.Value;
quotient.Enabled= (add2 !=0) && (add1 / add2 != quotient.Value);
//etc
}
I came across this while doing some research and would like to give my solution I used for my situation and hope it helps people. I needed minimum and maximum numbers for a calculation, so mine are named appropriately and I correlated these with some CheckBoxes. I used null in beginning of minimum and end of maximum to account for empty. I also had to create an event handler SubscribeToEvents() shown below.
In my load event for my form:
SubscribeToEvents();
_checkBoxs = new[] { cbXLight, cbLight, cbMedium, cbHeavy, cbXHeavy, cbXXHeavy, cbXXXHeavy };
_minimumsNumericUpDowns = new[] { null, nLightMin, nMediumMin, nHeavyMin, nXHeavyMin, nXXHeavyMin, nXXXHeavyMin };
_maximumsNumericUpDowns = new[] { nXLightMax, nLightMax, nMediumMax, nHeavyMax, nXHeavyMax, nXXHeavyMax, null };
then I created a method:
private void DisableNumericUpDowns()
{
// disable everything:
foreach (var n in _minimumsNumericUpDowns)
{
if (n != null)
n.Enabled = false;
}
foreach (var n in _maximumsNumericUpDowns)
{
if (n != null)
n.Enabled = false;
}
}
The event handler:
private bool _eventsSubscribed;
private void SubscribeToEvents()
{
if (_eventsSubscribed)
return;
_eventsSubscribed = true;
cbXXHeavy.CheckedChanged += CheckBox_NumericState;
cbXHeavy.CheckedChanged += CheckBox_NumericState;
cbXLight.CheckedChanged += CheckBox_NumericState;
cbHeavy.CheckedChanged += CheckBox_NumericState;
cbLight.CheckedChanged += CheckBox_NumericState;
cbMedium.CheckedChanged += CheckBox_NumericState;
cbXXXHeavy.CheckedChanged += CheckBox_NumericState;
}
Now I can used this to check when they are enabled and if they are greater than or less than 0 if needed in the method CheckBox:
private void CheckBox_NumericState(object sender, EventArgs e)
{
// disable everything
DisableNumericUpDowns();
// see if more than one checkbox is checked:
var numChecked = _checkBoxs.Count((cb) => cb.Checked);
// enable things if more than one item is checked:
if (numChecked <= 1) return;
// find the smallest and enable its max:
var smallest = -1;
for (var i = 0; i < _checkBoxs.Length; i++)
{
if (!_checkBoxs[i].Checked) continue;
if (_maximumsNumericUpDowns[i] != null)
{
_maximumsNumericUpDowns[i].Enabled = true;
}
smallest = i;
break;
}
// find the largest and enable its min:
var largest = -1;
for (var i = _checkBoxs.Length - 1; i >= 0; i--)
{
if (!_checkBoxs[i].Checked) continue;
if (_minimumsNumericUpDowns[i] != null)
{
_minimumsNumericUpDowns[i].Enabled = true;
}
largest = i;
break;
}
// enable both for everything between smallest and largest:
var tempVar = largest - 1;
for (var i = (smallest + 1); i <= tempVar; i++)
{
if (!_checkBoxs[i].Checked) continue;
if (_minimumsNumericUpDowns[i] != null)
{
_minimumsNumericUpDowns[i].Enabled = true;
}
if (_maximumsNumericUpDowns[i] != null)
{
_maximumsNumericUpDowns[i].Enabled = true;
}
}
}
So I can check each state as required:
I want to check if Extra Light is check:
// Extra Light
if (!cbXLight.Checked) return;
if (nXLightMax.Enabled == false)
{
_structCategoryType = XLight;
CheckStructureSheets();
}
else
{
if (nXLightMax.Value > 0)
{
_dMax = nXLightMax.Value;
_structCategoryType = XLight;
CheckStructureSheets();
}
else
{
MessageBox.Show(#"Extra Light Max cannot be zero (0)");
}
}
and next light checks both:
// Light
if (cbLight.Checked)
{
if (nLightMin.Enabled == false && nLightMax.Enabled == false)
{
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
if (nLightMin.Enabled && nLightMin.Value > 0)
{
if (nXLightMax.Enabled && nLightMin.Enabled && nLightMax.Enabled == false)
{
_dMin = nLightMin.Value;
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
if (nLightMax.Value > 0)
{
_dMin = nLightMin.Value;
_dMax = nLightMax.Value;
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
MessageBox.Show(#"Light Max cannot be zero (0)");
return;
}
}
}
else if (nLightMin.Enabled == false && nLightMax.Enabled)
{
if (nLightMax.Value > 0)
{
_dMax = nLightMax.Value;
_structCategoryType = Light;
CheckStructureSheets();
}
else
{
MessageBox.Show(#"Light Max cannot be zero (0)");
}
}
else
{
MessageBox.Show(#"Light Min cannot be zero (0)");
return;
}
}
}
Hope this helps someone.
Tim
thanks for #AlexJoliq and #BrettCaswell. just want to inform that before Alex edited his answer from using "==" to "!=", i (thought) already solved the problem. but i don't know where is the more effective and efficient way, alex's or mine.
below is my code for DisableIfValueIsTrue():
if (add1 + add2 == sum.Value) sum.Enabled = false;
if (add1 - add2 == difference.Value) difference.Enabled = false;
if (add1 * add2 == product.Value) product.Enabled = false;
if (add1 / add2 == quotient.Value) quotient.Enabled = false;
Related
For an internship project I'm making an app based on Foley sound effects. I made a game for it. One button generates the effect, one plays the sound and four buttons for possible awnsers.
Somehow, the text displays ('helaas' and 'juist!') aren't consistent. The awnser could be right and it will display 'helaas', but when clicken multiple times, it will display 'juist!'. Can anyone help me with what I am doing wrong here?
int kiesnummer()
{
Random randomSound = new Random();
int theSound = randomSound.Next(1, 4);
return theSound;
}
NewSound.Click += delegate
{
kiesnummer();
if (kiesnummer() == 1)
{
welk.Text = "Open haard";
}
else if (kiesnummer() == 2)
{
welk.Text = "Regen";
}
else if (kiesnummer() == 3)
{
welk.Text = "Hondenpootjes op hout";
}
else if (kiesnummer() == 4)
{
welk.Text = "Paardenhoeven op beton";
}
};
Play.Click += delegate
{
if (kiesnummer() == 1)
{
_chips.Start();
}
else if (kiesnummer() == 2)
{
_rain.Start();
}
else if (kiesnummer() == 3)
{
_doggo.Start();
}
else if(kiesnummer() == 4)
{
_koko.Start();
}
};
//Parameters aan functie koppelen bij klikken op de knop
Aw1.Click += delegate
{
kiesknop(1);
};
Aw2.Click += delegate
{
kiesknop(2);
};
Aw3.Click += delegate
{
kiesknop(3);
};
Aw4.Click += delegate
{
kiesknop(4);
};
//Beoordelen of keuze juist of onjuist is
bool kiesknop(int knop)
{
if (knop == kiesnummer())
{
end.Text = "Juist!";
return true;
}
else
{
end.Text = "Helaas!";
return false;
}
}
(I left the button and media declerations out, since it didn't seem relevant)
Calling kiesnummer(); in every if condition will give you different results as it generates new random value every time.
Call it once and use its value through-out:
int value = kiesnummer();
if (value == 1)
{
welk.Text = "Open haard";
}
else if (value == 2)
{
welk.Text = "Regen";
}
else if (value) == 3)
{
welk.Text = "Hondenpootjes op hout";
}
else if (value == 4)
{
welk.Text = "Paardenhoeven op beton";
}
I want realize arithmetic operations with my list, in this case:
Column "width" * Column "height" should re-Write the Column "Partial".
I have tried do a loop but It is not working.
I put a breakPoint at the row:
_Area[i].Partial = _Area[i].width * _Area[i].height;
And the debug never stop them I can think this line is not been readed.
This is my Collection View Model:
public class CollectionVM_Area : BindableBase
{
private Values_Area _Area = new Values_Area();
public Values_Area Area
{
get { return _Area; }
set { SetProperty(ref _Area, value); }
}
public CollectionVM_Area()
{
_Area.Add(new Area()
{
width=10,
height=11,
});
_Area.Add(new Area()
{
width=5,
height=5,
Partial=1,
});
bool NeedPartial = false;
int i = 0;
while (NeedPartial = false && i < _Area.Count)
{
if (_Area[i].Partida == true)
{
NeedPartial = true;
}
else
{
i++;
}
}
if (NeedPartial==true)
{
_Area[i].Partial = _Area[i].width * _Area[i].height;
NeedPartial = false;
}
else
{
NeedPartial = true;
}
}
}
My Project is a UWP but I think is no different in with a windows forms in lists, any help is appreciated.
You have two mistalkes in your code. First your while-loop makes an assignement instead of a comparisson (= towards ==). Thus the first term within your while-condition allways evaluates to false. Secondly your calculation is located outside the loop causing the NeedPartial-value to be set but not never be read which I doubt is what you want.
Write this therefor:
bool NeedPartial = false;
int i = 0;
while (NeedPartial == false && i < _Area.Count) // or even simpler: while (!NeedPartial ...)
{
if (_Area[i].Partida == true) // or simply: if (_Area[i].Partida) { ... }
{
NeedPartial = true;
}
else
{
i++;
}
if (NeedPartial==true) // if (NeedPartial) ...
{
_Area[i].Partial = _Area[i].width * _Area[i].height;
NeedPartial = false;
}
else
{
NeedPartial = true;
}
}
Edit: Answered.
The Correct Loop is:
bool NeedPartial = false;
int i = 0;
while (!NeedPartial && i < _Area.Count)
{
if (_Area[i].Partida)
{
NeedPartial = true;
}
else
{
i++;
}
if (NeedPartial)
{
_Area[i].Partial = _Area[i].width * _Area[i].height;
NeedPartial = false;
i++;
}
else
{
NeedPartial = true;
}
}
Thanks to HimBromBeere for your help.
I made this function to select the item on DataGrid on user keypress. If the user key is "A" it will select the first item where username starts with letter "A". If the user key is again "A" it will select the next item where username starts with letter "A" and so on. The function works great, but what I want is when there are no more items where username starts with "A" to start over (select the first item), it currently remains on the last item where username start with letter "A".
private static Key lastKey;
private static int lastFoundIndex = 0;
public static void AccountsDataGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if ((dataGrid.Items.Count == 0) && !(e.Key >= Key.A && e.Key <= Key.Z))
{
return;
}
if ((lastKey != e.Key) || (lastFoundIndex == dataGrid.Items.Count - 1))
{
lastFoundIndex = 0;
}
for (int i = lastFoundIndex; i < dataGrid.Items.Count; i++)
{
if (dataGrid.SelectedIndex == i)
{
continue;
}
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
lastFoundIndex = i;
break;
}
}
lastKey = e.Key;
}
Update (with solution):
Inspired by Danielle's idea, I have changed my code like below, works like a charm.
private static Key lastKey;
private static int lastFoundIndex = 0;
public static void AccountsDataGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if ((dataGrid.Items.Count == 0) && !(e.Key >= Key.A && e.Key <= Key.Z))
{
return;
}
if ((lastKey != e.Key) || (lastFoundIndex == dataGrid.Items.Count - 1))
{
lastFoundIndex = 0;
}
Func<object, bool> itemCompareMethod = (item) =>
{
Account account = item as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
return true;
}
return false;
};
lastFoundIndex = FindDataGridRecordWithinRange(dataGrid, lastFoundIndex, dataGrid.Items.Count, itemCompareMethod);
if (lastFoundIndex == -1)
{
lastFoundIndex = FindDataGridRecordWithinRange(dataGrid, 0, dataGrid.Items.Count, itemCompareMethod);
}
if (lastFoundIndex != -1)
{
dataGrid.ScrollIntoView(dataGrid.Items[lastFoundIndex]);
dataGrid.SelectedIndex = lastFoundIndex;
}
if (lastFoundIndex == -1)
{
lastFoundIndex = 0;
dataGrid.SelectedItem = null;
}
lastKey = e.Key;
}
private static int FindDataGridRecordWithinRange(DataGrid dataGrid, int min, int max, Func<object, bool> itemCompareMethod)
{
for (int i = min; i < max; i++)
{
if (dataGrid.SelectedIndex == i)
{
continue;
}
if (itemCompareMethod(dataGrid.Items[i]))
{
return i;
}
}
return -1;
}
The solution you wound up with is needlessly complex and checks rows it doesn't need to check. The two static variables to maintain state are not needed either. Try this instead:
public void MainGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (dataGrid.Items.Count == 0 || e.Key < Key.A || e.Key > Key.Z)
{
return;
}
Func<object, bool> doesItemStartWithChar = (item) =>
{
Account account = item as Account;
return account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.InvariantCulture);
};
int currentIndex = dataGrid.SelectedIndex;
int foundIndex = currentIndex;
// Search in following rows
foundIndex = FindMatchingItemInRange(dataGrid, currentIndex, dataGrid.Items.Count - 1, doesItemStartWithChar);
// If not found, search again in the previous rows
if (foundIndex == -1)
{
foundIndex = FindMatchingItemInRange(dataGrid, 0, currentIndex - 1, doesItemStartWithChar);
}
if (foundIndex > -1) // Found
{
dataGrid.ScrollIntoView(dataGrid.Items[foundIndex]);
dataGrid.SelectedIndex = foundIndex;
}
}
private static int FindMatchingItemInRange(DataGrid dataGrid, int min, int max, Func<object, bool> doesItemStartWithChar)
{
for (int i = min; i <= max; i++)
{
if (dataGrid.SelectedIndex == i) // Skip the current selection
{
continue;
}
if (doesItemStartWithChar(dataGrid.Items[i])) // If current item matches the string, return index
{
return i;
}
}
return -1;
}
Regarding your comment, just add this check:
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
{
return;
}
You could extract your for-loop into a separate method that determines if another item was found.
public int FindRecordWithinRange(DataGrid dataGrid, int min, int max)
{
for (int i = min; i < max; i++)
{
if (dataGrid.SelectedIndex == i)
continue;
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
return i;
}
}
return -1;
}
And call into it using something like this:
lastFoundIndex = FindRecordWithinRange(dataGrid, lastFoundIndex, dataGrid.Items.Count);
if (lastFoundIndex == -1)
lastFoundIndex = FindRecordWithinRange(dataGrid, 0, dataGrid.Items.Count);
if (lastFoundIndex == -1)
dataGrid.SelectedItem = null;
This would basically attempt to search the list from the beginning and would also handle the case where no items were found by clearing out the selection. You might also want to scroll to the beginning in this case, handling at this point is dependent on what you want to do.
Another thing you might want to do here is extract your ScrollIntoView and Selection logic and handle that after the index has been determined.
if i change my function like below, it will stay 2 times on the last item for letter "A" before going to the first item with letter "A" (assuming the user key is still "A").
private static Key lastKey;
private static int lastFoundIndex = 0;
public static void AccountsDataGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if ((dataGrid.Items.Count == 0) && !(e.Key >= Key.A && e.Key <= Key.Z))
{
return;
}
if ((lastKey != e.Key) || (lastFoundIndex == dataGrid.Items.Count - 1))
{
lastFoundIndex = 0;
}
for (int i = lastFoundIndex; i < dataGrid.Items.Count; i++)
{
if ((lastFoundIndex > 0) && (lastFoundIndex == i))
{
lastFoundIndex = 0;
}
if (dataGrid.SelectedIndex == i)
{
continue;
}
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
lastFoundIndex = i;
break;
}
}
lastKey = e.Key;
}
Your code says that to start searching again from the beginning, the lastFoundIndex should be equal to dataGrid.Items.Count - 1 (supposing the same key was pressed again).
But your last found Account may be not at the end of the Items collection, so that the lastFoundIndex was not set to dataGrid.Items.Count - 1 when the previous key was pressed. In this case your condition to start over again is not fulfilled.
Try changing the last-found checking and the "for" loop like this:
bool found = false;
bool lastFound = true;
if (lastKey != e.Key || lastFound)
{
lastFoundIndex = 0;
}
for (int i = lastFoundIndex; i < dataGrid.Items.Count; i++)
{
if (dataGrid.SelectedIndex == i)
{
continue;
}
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
if (!found)
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
lastFoundIndex = i;
found = true;
}
else
{
lastFound = false;
break;
}
}
}
Basically it will try to find one more item to see if it was the last match or not.
This line of (C#) code
if (!currentLap.S1.HasValue)
is giving me
System.NullReferenceException: Object reference not set to an instance of an object.
provided I'm sure that currentLap variable is instantiated (because it's being used a few lines before and it is a local variable) and it has following property:
private double? _s1;
[DefaultValue(null)]
[JsonConverter(typeof(ShortDoubleConverter))]
public double? S1
{
get { return _s1; }
set { _s1 = value; }
}
how can it possibly throw NullReferenceException? Can it be something to do with optimization on Release mode?
Thanks,
Stevo
EDIT:
here is full method code.
public void Update(DriverData driverData)
{
LapInfo currentLap = this.CurrentLap;
if (currentLap != null &&
this.LastDriverData != null &&
driverData.TotalLaps != this.LastDriverData.TotalLaps &&
driverData.InPits &&
driverData.Speed < 10 &&
!this.LastDriverData.InPits)
{
currentLap.Escaped = true;
}
this.LastDriverData = driverData;
if ((currentLap == null || currentLap.Lap != driverData.LapNumber) &&
!this.Laps.TryGetValue(driverData.LapNumber, out currentLap))
{
currentLap = new LapInfo() { Lap = driverData.LapNumber, Parent = this, Class = driverData.Class };
this.Laps.Add(driverData.LapNumber, currentLap);
int lapsCount = 0, completedDriverLaps = 0, cleanLaps = 0;
this.TotalLaps = driverData.TotalLaps;
//if it's not the first lap
if (driverData.TotalLaps > 0)
{
//previous lap
if (this.CurrentLap == null || !this.CurrentLap.Escaped)
{
this.CompletedLaps++;
if (this.CurrentLap == null || !this.CurrentLap.MaxIncident.HasValue)
this.CleanLaps++;
}
}
foreach (DriverLapsInfo laps in this.Parent.LapsByVehicle.Values)
{
lapsCount += laps.TotalLaps;
completedDriverLaps += laps.CompletedLaps;
cleanLaps += laps.CleanLaps;
}
this.Parent.Parent.SetLapsCount(driverData, lapsCount, driverData.Class, completedDriverLaps, cleanLaps);
}
this.CurrentLap = currentLap;
//add incidents
if (driverData.Incidents != null)
{
foreach (IncidentScore incident in driverData.Incidents)
{
this.CurrentLap.MaxIncident = Math.Max(this.CurrentLap.MaxIncident ?? 0, incident.Strength);
this.CurrentLap.Incidents++;
this.Incidents++;
}
}
LapInfo previousLap = null;
if ((this.PreviousLap == null || this.PreviousLap.Lap != driverData.TotalLaps) &&
this.Laps.TryGetValue(driverData.TotalLaps, out previousLap))
{
this.PreviousLap = previousLap;
if (!this.PreviousLap.Date.HasValue)
{
this.PreviousLap.Date = DateTime.UtcNow;
}
}
if (currentLap.Position == 0)
currentLap.Position = driverData.Position;
if (driverData.CurrentS1 > 0)
{
**if (!currentLap.S1.HasValue)**
{
this.UpdateBestS1(driverData.BestS1);
this.Parent.Parent.UpdateBestS1(driverData.BestS1, driverData.UniqueName);
currentLap.UpdateS1(driverData.CurrentS1, driverData);
//reset the best split set at the finish line
if (this.PreviousLap != null && this.PreviousLap.SplitBest < 0)
this.PreviousLap.SplitBest = 0;
}
if (driverData.CurrentS2.HasValue && driverData.CurrentS1.HasValue && !currentLap.S2.HasValue)
{
double s2 = driverData.CurrentS2.Value - driverData.CurrentS1.Value;
this.UpdateBestS2(s2);
this.Parent.Parent.UpdateBestS2(s2, driverData.UniqueName);
currentLap.UpdateS2(s2, driverData);
}
}
if (this.PreviousLap != null)
{
if (driverData.LastLap > 0)
{
if (!this.PreviousLap.S3.HasValue && driverData.LastS2.HasValue)
{
double s3 = driverData.LastLap.Value - driverData.LastS2.Value;
this.UpdateBestS3(s3);
this.Parent.Parent.UpdateBestS3(s3, driverData.UniqueName);
this.PreviousLap.UpdateS3(s3, driverData);
}
if (!this.PreviousLap.LapTime.HasValue)
{
double? bestLap = this.Parent.Parent.BestLap;
this.PreviousLap.UpdateLapTime(driverData, 0);
this.Parent.Parent.UpdateBestLap(this.PreviousLap, driverData.BestLap, driverData);
this.UpdateBestLap(driverData.BestLap, this.PreviousLap);
this.PreviousLap.UpdateLapTime(driverData, bestLap);
}
}
else
{
if (this.PreviousLap.SplitBest.HasValue)
this.PreviousLap.UpdateBestSplit();
if (this.PreviousLap.SplitSelf.HasValue)
this.PreviousLap.UpdateSelfSplit();
}
}
if (driverData.InPits)
{
switch (driverData.Sector)
{
case Sectors.Sector1:
if (previousLap != null)
previousLap.InPits = true;
break;
case Sectors.Sector3:
currentLap.InPits = true;
break;
}
}
//lap to speed
if (currentLap.TopSpeed < driverData.Speed)
{
driverData.TopSpeedLap = driverData.Speed;
currentLap.UpdateTopSpeed(driverData.Speed);
}
else
driverData.TopSpeedLap = currentLap.TopSpeed;
//overall top speed
if (this.TopSpeed < driverData.Speed)
{
driverData.TopSpeed = driverData.Speed;
this.TopSpeed = driverData.Speed;
this.Parent.Parent.UpdateTopSpeed(this.TopSpeed, driverData);
}
else
driverData.TopSpeed = this.TopSpeed;
}
There is no way on earth the code can make it to that line and currentLap beeing null.
Or am I going crazy? :)
.HasValue will not throw if the nullable reference is null, but a.b.HasValue will if a is null.
I suspect that currentLap == null. I know you say you're sure that currentLap is not null, but I think that's the most likely explanation. Can you post more code?
Update:
Thanks for posting your code.
This doesn't throw:
void Main() {
var f = new Foo();
Console.WriteLine (f.S1);
Console.WriteLine (f.S1.HasValue);
}
class Foo {
private double? _s1 = null;
public double? S1 {
get { return _s1; }
set { _s1 = value; }
}
}
Could you try to create a minimal reproduction? (minimal code that exhibits the issue)
Maybe have a look at the previous line of code :) - debugger often highlights the next line after the one where the NullReferenceException was actually thrown.
I'm trying to understand what's happening here. I have a CheckedListBox which contains some ticked and some un-ticked items. I'm trying to find a way of determining the delta in the selection of controls. I've tried some cumbersome like this - but only works part of the time, I'm sure there's a more elegant solution. A maybe related problem is the myCheckBox_ItemCheck event fires on form load - before I have a chance to perform an ItemCheck. Here's what I have so far:
void clbProgs_ItemCheck(object sender, ItemCheckEventArgs e)
{
// i know its awful
System.Windows.Forms.CheckedListBox cb = (System.Windows.Forms.CheckedListBox)sender;
string sCurrent = e.CurrentValue.ToString();
int sIndex = e.Index;
AbstractLink lk = (AbstractLink)cb.Items[sIndex];
List<ILink> _links = clbProgs.DataSource as List<ILink>;
foreach (AbstractLink lkCurrent in _links)
{
if (!lkCurrent.IsActive)
{
if (!_groupValues.ContainsKey(lkCurrent.Linkid))
{
_groupValues.Add(lkCurrent.Linkid, lkCurrent);
}
}
}
if (_groupValues.ContainsKey(lk.Linkid))
{
AbstractLink lkDirty = (AbstractLink)lk.Clone();
CheckState newValue = (CheckState)e.NewValue;
if (newValue == CheckState.Checked)
{
lkDirty.IsActive = true;
}
else if (newValue == CheckState.Unchecked)
{
lkDirty.IsActive = false;
}
if (_dirtyGroups.ContainsKey(lk.Linkid))
{
_dirtyGroups[lk.Linkid] = lkDirty;
}
else
{
CheckState oldValue = (CheckState)e.NewValue;
if (oldValue == CheckState.Checked)
{
lkDirty.IsActive = true;
}
else if (oldValue == CheckState.Unchecked)
{
lkDirty.IsActive = false;
}
_dirtyGroups.Add(lk.Linkid, lk);
}
}
else
{
if (!lk.IsActive)
{
_dirtyGroups.Add(lk.Linkid, lk);
}
else
{
_groupValues.Add(lk.Linkid, lk);
}
}
}
Then onclick of a save button - I check whats changed before sending to database:
private void btSave_Click(object sender, EventArgs e)
{
List<AbstractLink> originalList = new List<AbstractLink>(_groupValues.Values);
List<AbstractLink> changedList = new List<AbstractLink>(_dirtyGroups.Values);
IEnumerable<AbstractLink> dupes = originalList.ToArray<AbstractLink>().Intersect(changedList.ToArray<AbstractLink>());
foreach (ILink t in dupes)
{
MessageBox.Show("Changed");
}
if (dupes.Count() == 0)
{
MessageBox.Show("No Change");
}
}
For further info. The definition of type AbstractLink uses:
public bool Equals(ILink other)
{
if (Object.ReferenceEquals(other, null)) return false;
if (Object.ReferenceEquals(this, other)) return true;
return IsActive.Equals(other.IsActive) && Linkid.Equals(other.Linkid);
}
There's little point that I see to do this in the ItemCheck event. Just calculate the delta when you save. Cuts out a bunch of code and trouble with spurious events.