Check if all the buttons in an array are active - c#

Is there a way to check if all the buttons in an array are active or not, all at once? I am using for loop to determine it but the break; does not really signify anything that I want to achieve.
public Button[] bts;
public void StateButton()
{
for (int i = 0; i < bts.Length; ++i)
{
if (!bts[i].interactable)
{
Debug.Log("all buttons are off");
break;
}
else
{
Debug.Log("atleast one is on");
}
}
}

It is possible using LINQ:
var allInteractable = bts.All(e => e.interactable)
Depending on the length of the array and the expected state of the buttons (i.e. you know that almost all the time at least one button is not interactable) it might be more performant to inverse the query using:
var atLeastOneNonInteractable = bts.Any(e => !e.interactable)

Your debug logs don't really match with the title of your question.
Written out it should either be
public bool StateButton()
{
var allOn = true;
foreach (var btn in bts)
{
if (!btn.interactable)
{
allOn = false;
break;
}
}
Debug.Log(allOn ? "All buttons on" : "At least one button off");
return allOn;
}
or
public bool StateButton()
{
var anyOn = false;
foreach (var btn in bts)
{
if (btn.interactable)
{
anyOn = true;
break;
}
}
Debug.Log(anyOn ? "At least one button on" : "All buttons off");
return anyOn;
}
depending on your needs.
And then you already have Michael Mairegger's answer using Linq to shorten this into a single line ;)

Related

Add back/forward buttons for viewing different Treeview Items without breaking limits

I want to navigate between some TreeViewItem using back/forward buttons. I can actually do that but my problem is that i can't make it stop going outside the limits. There's an example of my code for a forward button:
private void MainUser_button_next_Click(object sender, RoutedEventArgs e)
{
int index = 0;
foreach (TreeViewItem i in TreeviewUsers.Items)
{
if (i.Equals(MainTreeView.SelectedItem))
{
break;
}
index++;
}
(TreeviewUsers.Items[index + 1] as TreeViewItem).IsSelected = true;
}
With the code I'm showing above it is possible to navigate forward but it breaks after it gets more that it's limits. I know I need to bind a limit but I don't know where to do that!
Thanks in advance!
Here's a possible answer, depending on the behavior you want
(TreeviewUsers.Item[(index+1)%TreeviewUser.Item.Count] as TreeViewitem).IsSelected = true;
or this line (try for the back case)
(TreeviewUsers.Item[mod((index+1),TreeviewUser.Item.Count)] as TreeViewitem).IsSelected = true;
and define somewhere
int mod(int x, int m) {
int r = x%m;
return r<0 ? r+m : r;
}
By the way, can't you change this code
int index = 0;
foreach (TreeViewItem i in TreeviewUsers.Items)
{
if (i.Equals(MainTreeView.SelectedItem))
{
break;
}
index++;
}
with this here
int index = TreeviewUsers.Items.Select((v, i) => new {v, i}).Where(x => x.v.Equals(MainTreeView.SelectedItem)).Select(x => x.i);

How to get next value from List<string>

I have problem with List string. I put 3 values into myCollection
List<string> myCollection = new List<string>();
myCollection.Add(Encoding.Default.GetString(data));
myCollection.Add(Encoding.Default.GetString(data2));
myCollection.Add(Encoding.Default.GetString(data3));
and now i have 3 values : A,B,C
but now i want to block buttons with contains this values :
for (var i = 0; i < myCollection.Count; i++)
{
if (myCollection.Contains(A))
{
this.A.Enabled = false;
}
else if (myCollection.Contains(B))
{
this.B.Enabled = false;
}
else if (myCollection.Contains(C))
{
this.C.Enabled = false;
}
}
After this loop just first button=false. Now loop done 3 times this same try block button A and my question is:
How block other buttons?
Now i get in first loop run:
this.A.Enabled = false;
2nd this.A.Enabled = false;
3rd this.A.Enabled = false;
but i want :
1st : this.A.Enabled = false;
2nd : this.B.Enabled = false;
3rd : this.C.Enabled = false;
You don't need a loop for this. Just use simple if statements without else.
if (myCollection.Contains("A"))
this.A.Enabled = false;
if (myCollection.Contains("B"))
this.B.Enabled = false;
if (myCollection.Contains("C"))
this.C.Enabled = false;
Mainly the else was causing problems for you. If the condition for A was true, then the code for B and C did not run. This is how else works.
Not sure what exactly are you trying to achieve, but your problem here is that you use if..else. If any of the conditions is true, the rest won't be resolved.
To solve your problem just remove the else keywords from your conditions.
Also, the loop is unnecesary when you use Contains.
If you'd insist on the loop, you would have to change the condition a bit, and then the else would be properly used:
for (int i = 0; i < myCollection.Count; i++)
{
if (myCollection[i] == A)
{
this.A.Enabled = false;
}
else if (myCollection[i] == B)
{
this.B.Enabled = false;
}
else if (myCollection[i] == C)
{
this.C.Enabled = false;
}
}

How to fail test if UI element is not found?

I use a method that searches an UI element:
public static bool findtopuielm(string uiitemname)
{
bool res = false;
try
{
AutomationElement desktopelem = AutomationElement.RootElement;
if (desktopelem != null)
{
Condition condition = new PropertyCondition(AutomationElement.NameProperty, uiitemname);
AutomationElement appElement = desktopelem.FindFirst(TreeScope.Descendants, condition);
if (appElement != null)
{
res = true;
}
}
return res;
}
catch (Win32Exception)
{
// To do: error handling
return false;
}
}
This method is called by another one that waits an element until it appears on desktop.
public static void waittopuielm(string appname, int retries = 1000, int retrytimeout = 1000)
{
for (int i = 1; i <= retries; i++)
{
if (findtopuielm(appname))
break;
Thread.Sleep(retrytimeout);
}
}
The thing is that when I call the last function for example:
waittopuielm("Test");
It always returns true even if the element is not found, in that case I want the test to fail.
Any suggestion would be welcomed.
It looks like your waittopuielem method returns void - did you mean to post something like this version, which returns a bool?
public static bool waittopuielm(string appname, int retries = 1000, int retrytimeout = 1000)
{
bool foundMatch = false;
for (int i = 1; i <= retries; i++)
{
if (findtopuielm(appname))
{
foundMatch = true;
break;
}
else
{
Console.WriteLine("No match found, sleeping...");
}
Thread.Sleep(retrytimeout);
}
return foundMatch;
}
Other than that, your code seems to work as expected for me.
One suggestion: In your findtopuielm method, change the TreeScope value in the desktop element search from TreeScope.Descendants to TreeScope.Children:
AutomationElement appElement = desktopelem.FindFirst(TreeScope.Children, condition);
TreeScope.Descendants is probably doing more recursive searching than you want - all children of the desktop element will be searched, as well as every child of those elements (i.e. buttons, edit controls, and so forth).
So, the chances of finding the wrong element when searching for a relatively common string are high, unless you combine your NameProperty PropertyCondition with other properties in an AndCondition to narrow your search.

List<T> moving to the next element

I searched SO and found some posts, but could not get them to work.
Question: How would I loop to the next item in my List Collection (custLoginHist[1] etc)?
List<eCommCustomer.oCustomer> custLoginHist = new List<eComm.oCustomer>();
eCommCustomerDAL.GetCustomerPrevLogin(custLoginHist, oCust);
if (custLoginHist.Count > 0)
{
eCommSecurityFactory oSecFactory = new eCommSecurityFactory();
if (oCust.CustHash == oSecFactory.CreateHash(custLoginHist[0].CustSalt, custLoginHist[0].CustHash))
{
//Password has been used before;
return false;
}
else
{
// Valid password;
return true;
}
}
return true;
}
foreach(eCommCustomer.oCustomer cust in custLoginHist)
{
//Do something with cust here.
}
OR:
for(int i = 0; i != custLoginHist.Count; ++i)
{
eCommCustomer.oCustomer cust = custLoginHist[i];
//Do something with cust here.
}
In this case, we want to return false for any single match, and true otherwise, so:
foreach(eCommCustomer.oCustomer cust in custLoginHist)
if(oCust.CustHash == oSecFactory.CreateHash(custLoginHist[0].CustSalt, custLoginHist[0].CustHash)
return false;
return true;//if we reached here, no matches.
This is a bad idea though, because you've made breaking into the system easier. If I try to set my password to something, and you refuse, I now know that one of your users uses that password. You are much better off letting this case happen, though you should perhaps be blocking some of the more likely offenders ("password", "password1", etc) with a quality check.
List<eCommCustomer.oCustomer> custLoginHist = new List<eComm.oCustomer>();
eCommCustomerDAL.GetCustomerPrevLogin(custLoginHist, oCust);
foreach (var custLogin in custLoginHist)
{
eCommSecurityFactory oSecFactory = new eCommSecurityFactory();
if (oCust.CustHash == oSecFactory.CreateHash(custLogin.CustSalt, custLogin.CustHash))
{
//Password has been used before;
return false;
}
}
return true;
Try something like this, maybe you have to customize your return statements but it should give you an insight how it works.
foreach(var item in yourList)
{
//Iterate;
}
If you want break , you can use : break;
If you want finish you can use : continue;
List<T> implements IEnumerable<T>, so you can just use foreach or if you to be able to edit T in the loop, you can use for.
foreach(var item in custLoginHist)
{
}
Or
for (int i = 0; i < custLoginHist.Count; i++)
{
}
Then if you need to exit out of the loop before it is completed (such as if you have a condition that is true, you can just use break; to exit the loop, or you can return from a loop too if you want to return a value.
You can you loop for this. For example foreach or for:
foreach (var custLogin in custLoginHist)
{
eCommSecurityFactory oSecFactory = new eCommSecurityFactory();
if (oCust.CustHash == oSecFactory.CreateHash(custLogin.CustSalt, custLogin.CustHash))
{
//Password has been used before;
return false;
}
else
{
// Valid password;
return true;
}
}
List<eCommCustomer.oCustomer> custLoginHist = new List<eComm.oCustomer>();
eCommCustomerDAL.GetCustomerPrevLogin(custLoginHist, oCust);
return custLoginHist.Select(c=>oSecFactory.CreateHash(c.CustSalt,c.CustHash))
.Any(x=>x==oCust.CustHash)

Threading issue - UI updates before the webservice has finished

I've searched for examples on how to fix
the problem below, but can't seem to find what I need and it's starting to
drive me potty!
Essentially, I have a race condition whereby the webservice is finishing way
after return has been given to the UI, so the UI is not displaying anything
at all.
Here's the code. The webservice does actually get the correct data which is
the pain of it all! The generateNewScreen method comes as a result of
clicking some text on a ListView area.
Calling routine
private void generateNewScreen(int t)
{
string[] races = new string[] { };
View currentview = FindViewById<View>(Resource.Id.relLayout);
TextView text = FindViewById<TextView>(Resource.Id.textTitle);
ListView listView = FindViewById<ListView>(Resource.Id.listView);
ImageView image = FindViewById<ImageView>(Resource.Id.imgBack);
image.Visibility = ViewStates.Visible;
Console.WriteLine("t = {0}, addFactor = {1}", t,addFactor);
switch (addFactor)
{
case 0:
switch (t)
{
case 0: races =listviewInfo(Resource.Array.RaceTracks,
Resource.Drawable.Back_RaceHorsePlace, Resource.String.Tracks);
addFactor = 10;
break;
case 1: List<string>
race = new List<string>();
currentview.SetBackgroundDrawable(Resources.GetDrawable(Resource.Drawable.Back_BobMoore));
text.Text = Resources.GetString(Resource.String.ComingSoon);
webservice_user getRace = new webservice_user();
race = getRace.getUpcomingRaces("RP");
races = race.ToArray();
addFactor = 20;
break;
}
if (t < 6 || t == 7)
listView.Adapter = new ArrayAdapter<string>(this, Resource.Layout.listview_layout, races);
break;
}
}
Webservice
private string rTrack;
public List<string> getUpcomingRaces(string track)
{
List<string> f = new List<string>();
rTrack = track;
getUpcomingRacesCallBack((list) =>
{
f = list;
});
return f;
}
private void getUpcomingRacesCallBack(Action<List<string>> callback)
{
List<string> f = new List<string>();
if (checkForNetwork(true) != true)
{
f.Add("No network available");
callback(f);
}
else
{
List<POHWS.webservice.UpcomingRaces> tableData = new List<POHWS.webservice.UpcomingRaces>();
POHWS.webservice.Service1 Service3 = new POHWS.webservice.Service1();
try
{
Service3.BeginGetUpcomingRacesList(rTrack, delegate(IAsyncResult iar)
{
tableData = Service3.EndGetUpcomingRacesList(iar).ToList();
Android.App.Application.SynchronizationContext.Post(delegate
{
if (tableData.Count == 0)
{
f.Add("No Upcoming Races Found within the next 7 days");
callback(f);
}
else
{
for (int i = 0; i < tableData.Count;++i)
f.Add(tableData[i].PostTime);
callback(f);
}
}, null);
}, null);
}
catch (Exception oe)
{
f.Add(oe.ToString());
callback(f);
}
}
}
Is it possible to either stop the UI or delay updating until the webservice
has done what it needs? I've tried quite a lot of things, but nothing gives.
The problem here is that getUpcomingRaces() is acting as if the call to getUpcomingRacesCallBack() is synchronous, and returns the list right away. Since it's very unlikely that the lambda would have fired before the return statement, it is always going to return the empty list.
I would suggest restructuring the code so that it acts on the list only once it's returned, similar to the approach you took with the getUpcomingRacesCallBack() method, which takes in an Action<List<string>>.
If it helps, I have a sample project available here that shows how to use this pattern. I also have a post here that talks about some different approaches to doing work off the UI thread, just in case you end up going the route of making the calls synchronous.

Categories

Resources