How to improve UI Selection logic? - c#

So I have this piece of code to select objects in the UI on hover, and to store the currently hovered element in the class scope with hoveredAction.
I feel like there would be a more elegant approach of this logic. I know that I could add one more check to avoid some computation if the raycasted object is the same as the stored one, but the "boilerplate" else if (hoveredAction != null) would persist.
This isn't the first time I come across this kind of logic, but this time it is simple enough for me to summarize it, any Idea would help.
void Update()
{
pointerEventData = new PointerEventData(eventSystem)
{
position = Input.mousePosition
};
List<RaycastResult> results = new();
raycaster.Raycast(pointerEventData, results);
if (results.Count > 0)
{
var result = results[0];
var obj = allowedActions.Where(a => result.gameObject == a.UiObject.gameObject);
if (obj.Count() > 0)
{
hoveredAction = obj.First();
hoveredAction.UiObject.GetComponent<Image>().color = shown;
}
else if(hoveredAction != null)
{
hoveredAction.UiObject.GetComponent<Image>().color = hidden;
hoveredAction = null;
}
}
else if (hoveredAction != null)
{
hoveredAction.UiObject.GetComponent<Image>().color = hidden;
hoveredAction = null;
}
}

Note that yours this is also not complete: In the case if (obj.Count() > 0) you also will want to set any previous hit to hidden ... or skip both if previous hit == current
I would split it up and only track the newCurrent hit an do e.g.
void Update()
{
pointerEventData = new PointerEventData(eventSystem)
{
position = Input.mousePosition
};
List<RaycastResult> results = new();
raycaster.Raycast(pointerEventData, results);
// whenever you deal with linq make sure to iterate only once!
Gamebject currentHoveredAction = results.Count == 0 ? null : allowedActions.Where(a => result.gameObject == a.UiObject.gameObject).FirstOrDefault();
// This is
// - either you hit a different object than before
// - you didn't hit anything before but do now
// - or you did hit something before but nothing now
if(hoveredAction != currentHoveredAction)
{
// if there is a previous hit reset it
if (hoveredAction != null)
{
hoveredAction.UiObject.GetComponent<Image>().color = hidden;
}
// if there is a current hit set it
if(currentHoveredAction != null)
{
currentHoveredAction.UiObject.GetComponent<Image>().color = show;
}
// either way store the new result
hoveredAction = currentHoveredAction;
}
}

Related

Code not reachting the lines in code which it should

For some reason, my code doesn't seem to reach the last few lines.
I've added the stop point and the return point in the code.
I don't see anything wrong with the data source I use on that row whenever I check it out in debug.
The code seems to set the value there and jumps back to the top of the foreach loop.
foreach (DataGridViewRow row in dataGridView1.Rows) {
//We check if the user has already filled in some info
return point if (row.Cells[7].Value != null && row.Cells[6].Value != null && !askedTheUser)
{
//trigger for message if you want to replace them
Message m = new Message("There is already info present in the category and or size dropdown. Would you like to overwrite this?", "Overwrite", "YESNO");
if (m.Awnser) {
overwrite = true;
}
askedTheUser = true;
}
DataGridViewComboBoxCell cat = (DataGridViewComboBoxCell)row.Cells[6];
string toMatch = row.Cells[3].Value.ToString();
//Now we will start matching
//First we try to match with the package ( if that is filled in )
if (row.Cells[5].Value != null && (string)row.Cells[5].Value != "") {
toMatch = row.Cells[5].Value.ToString();
matchWithPackage = true;
}
Regex re = new Regex(#"([a-zA-Z]+)(\d+)");
Match result = re.Match(toMatch);
string alphaPart = result.Groups[1].Value;
string numberPart = result.Groups[2].Value;
Datagridview dgv = new Datagridview();
if (numberPart.Length < 4) {
numberPart = numberPart.PadLeft(4, '0');
}
#if DEBUG
Console.WriteLine(numberPart);
#endif
//Matching the category
if (CHIP != null && CHIP.Contains(alphaPart))
{
cat.Value = "CHIP";
}
else if (SOJ != null && SOJ.Contains(alphaPart))
{
cat.Value = "SOJ";
}
else if (PLCC != null && PLCC.Contains(alphaPart))
{
cat.Value = "PLCC";
}
else if (QFP != null && QFP.Contains(alphaPart))
{
cat.Value = "QFP";
}
else if (SOP != null && SOP.Contains(alphaPart))
{
cat.Value = "SOP";
}
else {
if (cat.Value != "") {
cat.Value = "";
}
cat.FlatStyle = FlatStyle.Flat;
cat.Style.BackColor = Color.DarkRed;
continue;
}
//Setting the matched color
cat.FlatStyle = FlatStyle.Flat;
cat.Style.BackColor = Color.SpringGreen;
//Adding the dropdownlist to the size cb
(row.Cells[7] as DataGridViewComboBoxCell).DataSource = dgv.AddSeconderyCombobox(dataGridView1, row.Cells[6].Value.ToString());
if (!matchWithPackage) {
continue;
}
//Matching the size
Stop Point List<string> sizeList = (List<string>)(row.Cells[7] as DataGridViewComboBoxCell).DataSource;
Doesn't reach this and beyond List<string> matchedList = sizeList.FindAll(stringToCheck => stringToCheck.Contains(numberPart));
if (matchedList.Count > 0) {
(row.Cells[7] as DataGridViewComboBoxCell).DataSource = matchedList;
}
}
So i fixt my own problem and i'm going to awnser my own question i case somebody comes across a similar problem.
if (sizeList != null) {
List<string> matchedList = sizeList.FindAll(stringToCheck => stringToCheck.Contains(numberPart));
if (matchedList.Count > 0)
{
(row.Cells[7] as DataGridViewComboBoxCell).DataSource = matchedList;
}
}
After adding the few last lines in an extra check that needed to be done I noticed that the code was being executed, but the matchedlist.count was always 0.
So what was happening is that the code after that was redundant as the matchList was 0 and the debugger just skipped jumping to these lines ( a bit confusing if you ask me ).

ASP.Net - Mvc5 : LINQ , Saving duplicate record problem

I am coding daily counter. Database Counter Table is empty. If someone is my first visitor of current day, then I am adding a record to database and i am setting counter=1; After this, when other visitor visit current day, then i am increasing my counter++ and i am updating the record.
So I my records must be like this:
Date:2018-10-01 counter:23
Date:2018-10-02 counter:65
Date:2018-10-03 counter:20
Date:2018-10-04 counter:89
My problem is this: If the site get visitor same time, linq save 2 record for same day. Like this:
Date:2018-10-01 counter:23
Date:2018-10-02 counter:1 //First record: counter=1
Date:2018-10-02 counter:65 //Second record: counter=65
Date:2018-10-03 counter:20
Date:2018-10-04 counter:1 //First record
Date:2018-10-04 counter:89 //second record
Date must be unique. How can I resolve this problem? My code is below. Thanks a lot.
public static int IncreaseCounter_DailySiteVisitors()
{
int counter = 0;
using (var context = new MyProjectEntities())
{
try
{
string format = "dd.MM.yyyy";
DateTime Today = DateTime.Now;
var obj = (from record in context.CounterDailySiteVisitor
where
record.DateRecord != null
&& record.DateRecord.HasValue
&& record.DateRecord.Value.Year == Today.Year
&& record.DateRecord.Value.Month == Today.Month
&& record.DateRecord.Value.Day == Today.Day
select record).FirstOrDefault();
//var obj = context.CounterDailyVisitor.Where(x => x.DateRecord != null && ((DateTime)x.DateRecord).ToString("yyyy.MM.dd") == DateTime.Now.ToString("yyyy.MM.dd")).FirstOrDefault();
if (obj != null)
{
counter = obj.Count ?? 0;
counter++;
obj.Count = counter;
context.SaveChanges();
}
else
{
var newRecordObj = context.CounterDailySiteVisitor.Create();
newRecordObj.Count = 1;
newRecordObj.DateRecord = Today;
context.CounterDailySiteVisitor.Add(newRecordObj);
context.SaveChanges();
}
}
catch (Exception e)
{
}
}
return counter;
}
the chances of this being hit by two thread at the same time is quite low.
but i guess technically it can so you would need to wrap this in a lock
Something like below...
public static int IncreaseCounter_DailySiteVisitors()
{
private readonly object somethingObject = new object();
var context = new MyProjectEntities()
var today = DateTime.Now;
var todaysRecord = context.CounterDailyVisitor
.SingleOrDefault(x => x.DateRecord.Year == Today.Year
&& x.DateRecord.Month == Today.Month
&& x.DateRecord.Day == Today.Day
);
if (todaysRecord != null)
{
//the existing count + 1
todaysRecord.Count = todaysRecord.Count++;
}
else
{
Lock(somethingObject)
{
//recheck
var todaysRecord = context.CounterDailyVisitor
.SingleOrDefault(x => x.DateRecord.Year == Today.Year
&& x.DateRecord.Month == Today.Month
&& x.DateRecord.Day == Today.Day
);
if (todaysRecord != null)
{
//the existing count + 1
todaysRecord.Count = todaysRecord.Count++;
}
else
{
var newRecordObj = new CounterDailyVisitor();
newRecordObj.Count = 1;
newRecordObj.DateRecord = DateTime.Now; //this shouldnt be nullable
context.CounterDailySiteVisitor.Add(newRecordObj);
}
}
}
context.SaveChanges();
}
This is quite a common concurrency problem i.e. race condition. You will either have to Lock around the code that reads and subsequently updates/inserts the value. Or you should call a stored procedure and have all the logic inside the stored proc.
Lock comes with it's own set of issues if you're planning on using a web farm or running multiple instances of this MVC app.

multiple filters on ICollectionView with multiple condition checks WPF

This question has been asked before in different forms, but none answer my question. I have scraped this forum and Windows dev forum for info, before posting this. I cannot make sense of how to accomplish this task.
I am at my wits end.
I have a DataGrid that is binded to an ICollectionView. This data was pulled via a stored procedure and the DataGrid is automatically generated based on the columns in each table. For reference, the SP returns a list of objects, each with a series of members like stock_symbol, stock_price, Date etc.
There are a series of filters I would like to apply to this collection view. Two comboboxes and two datepickers, to be more specific. Each with a checkbox to signify they are active.
Each checkbox event handler stores the data that was selected from the combobox or the datepicker. I am trying to compare what is in those variables, to each relevant member of the object list and send that filtered object list back to the DataGrid.
This is my code:
private void FillDataGrid()
{
//Connect contains a simple stored procedure connection to SQL server
var Client = Connect();
DTOClass[] dTOs = Client.GetData();
SetDTOClass(dTOs);
MainGrid.ItemsSource = FilterView(dTOs);
}
Here is FilterView() (apologies for the long commented sections, I am trying to include my attempts in one foul sweep):
public ICollectionView /*List<DTOClass>*/ FilterView(DTOClass[] DTO)
{
if (_CollectionViewInternal == null)
{
//Assign collected DTO object to an ICollectionView
_CollectionViewInternal =
CollectionViewSource.GetDefaultView(DTO);
}
/*
ObservableCollection<DTOClass> DTOview = null;
if (DTOViewInternal == null)
{
int j = DTO.Length;
DTOview = new ObservableCollection<DTOClass>();
for(int i = 0; i < j; i++)
{
DTOview.Add(DTO[i]);
}
DTOViewInternal = DTOview;
}
*/
//Add a default sort description to the Date column
_CollectionViewInternal.SortDescriptions.Add(new SortDescription("Date", ListSortDirection.Ascending));
//assign our view to the maingrid (move this to later in the
//MainGrid.ItemsSource = _CollectionViewInternal;
if (MainGrid.ItemsSource != null)
{
/*List<Predicate<IEnumerable<DTOClass[]>>>*/ FilteredView = new List<Predicate<IEnumerable<DTOClass[]>>>();
//DateTime _zeroDay = new DateTime(1, 1, 1);
//DateTime _now = DateTime.Now;
FilteredView.Clear();
return FilteredView = _CollectionViewInternal.Where(Function(w) w.accountname.Contains(txtFilter.Text) _
Or w.firstname.Contains(txtFilter.Text) _
Or w.lastname.Contains(txtFilter.Text) _
Or w.isenabled.Contains(txtFilter.Text) _
Or w.description.Contains(txtFilter.Text) _
Or w.lastlogontimestamp.Contains(txtFilter.Text) _
Or w.whencreated.Contains(txtFilter.Text) _
Or w.whenchanged.Contains(txtFilter.Text) _
Or w.oulocation.Contains(txtFilter.Text) _
Or w.co.Contains(txtFilter.Text) _
Or w.l.Contains(txtFilter.Text) _
Or w.state.Contains(txtFilter.Text))
//if (yearsChosen > 0)
/* Stock, Maxadj, FromDate, ToDate */
/*
if (Stock_CheckBox.IsChecked != null)
{
FilteredView.Add(new Predicate<IEnumerable<DTOClass[]>>(x => x.Where(item => item. == Stock_ComboBoxText)));
}
if (letterChosen != "Any")
{
FilteredView.Add(new Predicate<IEnumerable<DTOClass[]>>(x => x.LastName.StartsWith(letterChosen)));
}
if (genderChosen != "Any")
{
FilteredView.Add(new Predicate<IEnumerable<DTOClass[]>>(x => x.Gender.Equals(genderChosen.Substring(0, 1))));
}
_CollectionViewInternal.Filter = dynamic_Filter;
RaisePropertyChanged("PeopleView");
// Bring the current person back into view in case it moved
if (CurrentPerson != null)
{
IEnumerable<DTOClass[]> current = CurrentPerson;
_CollectionViewInternal.MoveCurrentToFirst();
_CollectionViewInternal.MoveCurrentTo(current);
}
*/
/*
if (DTOview == null)
{
DTOview = DTOViewInternal;
} else
{
DTOViewInternal.
}
*/
//var collection = DTO;
//var symbol = collection.Where(item => item.Date == ).ToList();
//DTOview = new ObservableCollection<DTOClass>();
//IEnumerable<DTOClass> DTOview2;
//List<IEnumerable<DTOClass>> FilteredView = new List<IEnumerable<DTOClass>>();
/*
if (Stock_ComboBoxText != null)
{
//var collection = DTO;
var collection = DTO.Where(item => item.stock_symbol == Stock_ComboBoxText).Cast<DTOClass>().ToList();
//DTOview.Add(filtered.Cast<DTOClass>());
//FilteredView.Add(collection.Cast<DTOClass>());
FilteredView.Add(collection);
MainGrid.ItemsSource = FilteredView[0];
//FilteredView = filtered.Cast<DTOClass>();
}
if (Maxadj_ComboBoxText != 0)
{
var collection = DTO.Where(item => item.stock_price_adj_close == Maxadj_ComboBoxText).Cast<DTOClass>().ToList();
FilteredView.Add(collection);
MainGrid.ItemsSource = FilteredView[0];
//DTOview.Add(DTO.Where(item => item.stock_price_adj_close == ).ToList());
}
if (From_DatePickValue != null)
{
var collection = DTO.Where(item => item.Date >= From_DatePickValue).Cast<DTOClass>().ToList();
FilteredView.Add(collection);
MainGrid.ItemsSource = FilteredView[0];
}
if (To_DatePickValue != null)
{
var collection = DTO.Where(item => item.Date <= To_DatePickValue).Cast<DTOClass>().ToList();
FilteredView.Add(collection);
MainGrid.ItemsSource = FilteredView[0];
}
*/
//DTOview = DTOViewInternal;
//DTOview = null;
//DTOClass[] dto = GetDTOClass();
//ListCollectionView collectionView = new ListCollectionView(DTOViewInternal);
/*
collectionView.Filter = (e) =>
{
//int j = DTO.Length;
DTOClass[] dtofiltered = e as DTOClass[];
//for (int i = 0; i < j; i++)
//{
if ((Stock_ComboBoxText != null) && (DTOview[0][i].stock_symbol == Stock_ComboBoxText))
{
return true;
}
if ((Maxadj_ComboBoxText != 0) && (DTOview[0][i].stock_price_adj_close == Maxadj_ComboBoxText))
{
return true;
}
if ((From_DatePickValue != null) && (DTOview[0][i].Date >= From_DatePickValue))
{
return true;
}
if ((To_DatePickValue != null) && (DTOview[0][i].Date <= To_DatePickValue))
{
return true;
}
}
return true;
};
*/
//return collectionView.Cast<DTOClass>().ToList();
//return collectionView.Filter;
//return null;
//MainGrid.ItemsSource = null;
//MainGrid.ItemsSource = (CollectionView)CollectionViewSource.GetDefaultView(collectionView.ToString());
}
else
{
//MainGrid.ItemsSource = DTOview[0].ToList();
//MainGrid.ItemsSource = DTOview;
//return DTOview[0].ToList();
return _CollectionViewInternal;
}
return _CollectionViewInternal;
}
I only want to filter on a column, if it's relevant checkbox is checked. This is easy pickings with one filter, but more than one is proving to be beyond challenging.
As you can see I have attempted numerous solutions. I have tried using an ObservableCollection, I have tried filtering the object list directly and then adding it to an ICollectionView. Nothing works.
I have been attempting to graft this example: Complicated Filtering ICollectionView. But I cannot make heads or tails of it. I still don't understand predicates and tbh I really can't wrap my head around how it works.
I know it's frowned upon to ask 'gimme the code' questions. But if someone could just see past that and point out what I am doing wrong here, maybe even give me the code, I would be very grateful. I have spent weeks trying to understand this and I have run out of time on this assignment.
If not, then that's cool but please refrain from commenting on this thread. Don't take pride in withholding the answer either, I am usually an embedded C programmer and I just finished a full-sized OSX-Windows port for a massive Adobe AfterFX plugin. So I don't need snide remarks or any nonsense about putting more effort into learning, I just want to finish this assignment and be done with it.
Thank you all in advance.
Code to complement above comment:
List<Predicate<IEnumerable<DTOClass[]>>> FilteredView = null;
public ICollectionView FilterView(DTOClass[] DTO)
{
List<Predicate<IEnumerable<DTOClass[]>>>FilteredView = new
List<Predicate<IEnumerable<DTOClass[]>>>();
FilteredView.Clear();
if (Stock_CheckBox.IsChecked != null)
{
FilteredView.Add(new Predicate<IEnumerable<DTOClass[]>>(x => x.Where(item => item.stock_symbol == Stock_ComboBoxText)));
}
}
I can't even get the first predicate working. Apparently .stock_symbol isn't there and I can't index item. I suppose my real question here is how do I access the stock_symbol member?
Apologies for taking so long to get there, I am extremely sleep deprived.
EDIT:
Dumb mistakes are made with no sleep.
List<Predicate<DTOClass>> FilteredView = new List<Predicate<DTOClass>>();
if (Stock_CheckBox.IsChecked != null)
{
for (int i = 0; i < DTO.Length; i++)
{
FilteredView.Add(new Predicate<DTOClass>(x => x.stock_symbol == _Stock_ComboBoxText));
//FilteredView.Add(new Predicate<DTOClass[]>>(x => x.stock_symbol == _Stock_ComboBoxText));
}
}

What is this ArgumentOutOfRangeException caused by?

I have a problem that drives me nuts. I am using a generic List that throws an ArgumentOutOfRangeException whenever I try to assign its first (or last?) index to a variable. It's a pretty large pile of code, hence I'll try to extract only the relevant stuff. So here it is:
private string GetRuleByName(string name, List<string> rules)
{
if(rules != null)
{
List<string> todo = new List<string>();
todo.AddRange(rules);
while(rules.Count != 0)
{
string r = todo[0]; // <- Error 'ArgumentOutOfRangeException' here
todo.RemoveAt(0);
// ...
}
}
}
That's how I call the method:
void treeView_AfterSelect(object sender, TreeViewEventArgs e)
{
string currentRule = GetRuleByName(treeView.SelectedNode.FullPath, ruleCollection)
// the string list "ruleCollection" always contains
// strings and thus is never empty
}
Even though it's not a very detailed presentation of what's going on, as I had to cut off a piece of some complicated code, I really hope someone else might see what produces the error.
Big thanks in advance for at least having a look!
EDIT:
This is how the method looks like. I haven't altered anything, to show what's really inside it. I hope it makes sense for somebody:
private Rule GetRuleByNameOrId(string stName, List<Rule> rules)
{
if(rules != null)
{
string searchName = stName.ToLower().Trim();
string subName = "";
int slashPos = searchName.IndexOf('/');
if(slashPos != -1)
{
if(slashPos != searchName.Length)
subName = searchName.Substring(slashPos + 1);
searchName = searchName.Substring(0, slashPos);
}
List<Rule> todo = new List<Rule>();
todo.AddRange(rules);
while(todo.Count != 0)
{
Rule r = (Rule)todo[0];
todo.RemoveAt(0);
if(r.Name.ToLower() == searchName || r.Id.ToLower() == searchName)
{
if(subName != "")
{
Rule subRule = GetRuleByNameOrId(subName, r.Children);
if(subRule != null)
return subRule;
}
else
{
return r;
}
}
if(r.Children != null && r.Children.Count != 0)
todo.AddRange(r.Children);
}//end while
}//end if(rules != null)
return null;
}
Sounds like you want the following:
private string GetRuleByName(string name, List<string> rules)
{
if(rules != null)
{
List<string> todo = new List<string>();
todo.AddRange(rules);
while(todo.Count != 0) // <-- Minor mod here
{
string r = todo[0];
todo.RemoveAt(0);
// ...
}
}
}
Otherwise you are infinitely looping on rules.Count as the size of rules is not changing
This works fine until todo is empty, then you get the exception because element 0 no longer exists as you've removed them all!
Are you sure you don't want this instead:
while(rules.Count != 0)
{
string r = rules[0]; // <- Error 'ArgumentOutOfRangeException' here
rules.RemoveAt(0);
?
The way you've written it now, you've got a loop that would actually be infinite, except that you eventually remove all the elements from the todo list, at which point you throw the exception (because in an empty list even the 0-th element doesn't exist).

save children along with parent linq to sql

I have two tables Rule and RuleCondition (one -> many).
people can add conditions at any time.
Suppose initially he adds two conditions.
He can comeback and add another condition also can update the conditions that are already added.
I am able to save the updated conditions, but not able to insert the extra condition he added.
Below is my code, and it is failing at
rule.RuleConditions.Add(oRuleCon); -- Entity set was modified during enumaration
If I use the approach
oAngieCtxt.RuleConditions.InsertOnSubmit(oRuleCon);
it is not at all inserting the data.
can somebody advise how to handle?
public ActionResult saveMetricRule(Rule rule)
{
bool IsNew = rule.RuleId == 0;
using (NewAngieDataContext oAngieCtxt = new NewAngieDataContext(new CSConfigurationMgr().GetConnectionString(ConnectionStringKey.Angie)))
{
if (IsNew)
oAngieCtxt.Rules.InsertOnSubmit(rule);
else
{
RuleCondition oRuleCon = null;
foreach (RuleCondition childItem in rule.RuleConditions)
{
if (childItem.RuleConditionId == 0)
{
oRuleCon = new RuleCondition();
oRuleCon.Points = childItem.Points;
oRuleCon.ConditionValue = childItem.ConditionValue;
oRuleCon.ToOperatorId = childItem.ToOperatorId;
oRuleCon.Sort = childItem.Sort;
rule.RuleConditions.Add(oRuleCon);
// oAngieCtxt.RuleConditions.InsertOnSubmit(oRuleCon);
}
else
{
oRuleCon =
oAngieCtxt.RuleConditions
.Where(CON => CON.RuleConditionId == childItem.RuleConditionId)
.FirstOrDefault();
oRuleCon.Points = childItem.Points;
oRuleCon.ConditionValue = childItem.ConditionValue;
oRuleCon.ToOperatorId = childItem.ToOperatorId;
oRuleCon.Sort = childItem.Sort;
}
}
oAngieCtxt.Rules.Attach(rule);
oAngieCtxt.Refresh(RefreshMode.KeepCurrentValues, rule);
}
oAngieCtxt.SubmitChanges();
}
return this.Json(new
{
msg = "Successful save.",
ruleId = rule.RuleId
});
}
You can't add an item to a list that you're enumerating over. Since you're looping over the rule.RuleConditions, you can't add to it inside the foreach loop. Instead, you can add to a temporary list and then add all items from that list to the rule.RuleConditions after the foreach.
var newRuleConditions = new List<RuleCondition>();
foreach (RuleCondition childItem in rule.RuleConditions)
{
if (childItem.RuleConditionId == 0)
{
oRuleCon = new RuleCondition();
oRuleCon.Points = childItem.Points;
oRuleCon.ConditionValue = childItem.ConditionValue;
oRuleCon.ToOperatorId = childItem.ToOperatorId;
oRuleCon.Sort = childItem.Sort;
//add to temporary list
newRuleConditions.Add(oRuleCon);
oAngieCtxt.RuleConditions.InsertOnSubmit(oRuleCon);
}
else
{
...
}
}
//add all new rule conditions
rule.RuleConditions.AddRange(newRuleConditions);

Categories