I have a combobox with two items. I also have a button that opens a new form when one of these items are selected. However if none of the items are selected there is an exception(nullpointer). I have tried (to no avail) to catch this exception and show a mbox that prompts the user to choose one of the items.
Here is the code for the button click even:
if (labelGrid.Text == "Member" && cbTable.SelectedItem.ToString().Equals("Workout"))
{
string name;
string ss;
foreach (DataGridViewRow item in this.dtGrid1.SelectedRows)
{
ss = dtGrid1.CurrentCell.Value.ToString();
name = dtGrid1.SelectedCells[1].Value.ToString();
BookMemberWorkout bmw = new BookMemberWorkout(ss, name);
bmw.Label2.Text = ss;
bmw.Label1.Text = name;
bmw.ShowDialog();
}
}
You are not supposed to use exceptions for flow control in non-exceptional cases. The case that the user didn't select anything is surely not exceptional.
The correct approach would be a simple null check:
if(cbTable.SelectedItem == null)
{
// Show message box
}
else
{
// Your current code
}
Why your exception handling code isn't working is impossible to answer, because you didn't include it in your question.
I think the problem is in the line:
ss = dtGrid1.CurrentCell.Value.ToString();
You can't be sure the value is not null, so you should check it before calling the .ToString().
Instead of using a message box you could use a RequiredValidator to perform javascript validation, avoiding a useless postback.
From performance and readability point-of-view, I'd recommend checking for selected value in the combo box rather than catching an exception, like this
if(cbTable.SelectedItem == null)
{
MessageBox.Show("Please select a value in the combo box.");
return;
}
if (labelGrid.Text == "Member" && cbTable.SelectedItem.ToString().Equals("Workout"))
{
string name;
string ss;
foreach (DataGridViewRow item in this.dtGrid1.SelectedRows)
{
ss = dtGrid1.CurrentCell.Value.ToString();
name = dtGrid1.SelectedCells[1].Value.ToString();
BookMemberWorkout bmw = new BookMemberWorkout(ss, name);
bmw.Label2.Text = ss;
bmw.Label1.Text = name;
bmw.ShowDialog();
}
}
However to answer your specific query, you can catch NullReferenceException like this:
try{
if (labelGrid.Text == "Member" && cbTable.SelectedItem.ToString().Equals("Workout"))
{
string name;
string ss;
foreach (DataGridViewRow item in this.dtGrid1.SelectedRows)
{
ss = dtGrid1.CurrentCell.Value.ToString();
name = dtGrid1.SelectedCells[1].Value.ToString();
BookMemberWorkout bmw = new BookMemberWorkout(ss, name);
bmw.Label2.Text = ss;
bmw.Label1.Text = name;
bmw.ShowDialog();
}
}
}
catch(NullReferenceException ex)
{
MessageBox.Show("Please select a value in the combo box.");
}
Related
To be honest, I have no idea why the variable is being set to null. The object is set, then once I go through the DisplayPromptAsync, it sets the object to null.
I'm not sure what to try as I've never come across this issue.
Here's a gif of the issue. Once I enter into the field and press submit, an object gets reset.
async void OpenContainerItem()
{
// Pause the timer
blnTimerActive = false;
if (SelectedItem != null)
{
if (SelectedItem.intQuanChecked == SelectedItem.intQuantity)
return;
try
{
int intQuantity = 0;
// Ask for quantity
string result = await Application.Current.MainPage.DisplayPromptAsync("Quantity",
"How many " + SelectedItem.objItem.strItemName + " did you count?",
"Okay", cancel: "Cancel",
placeholder: "Quantity",
keyboard: Keyboard.Numeric);
// Check if it's been cancelled
if (result != null)
{
// check if theres nothing entered
if (result == "")
{
// Why tho?
await Application.Current.MainPage.DisplayAlert("Error", "Please enter a quantity.", "Okay");
}
else
{
intQuantity = int.Parse(result);
if (0 > ((SelectedItem.intQuantity - SelectedItem.intQuanChecked) - intQuantity))
{
Application.Current.MainPage.DisplayAlert("Error", "Thats too many items!", "Okay");
Reload();
blnTimerActive = true;
return;
}
modDatabaseUtilities.ContainerItemsPreCheck(SelectedItem.intContainerItemID, intQuantity, strCurrentUser);
Reload();
}
}
}
catch(Exception ex)
{
Application.Current.MainPage.DisplayAlert("Error", "Couldn't process this change. Please try again.", "Okay");
}
}
#ScottUphus - Is SelectedItem bound to a ListView? (If it is bound to anything, you should add that xaml in your question.) If so, then its a common problem: xamarin sets it back to null when the display layout is refreshed. (I'm not sure the exact "rule" for when it happens. In your case, I suspect the modal interaction causes this.)
This is how I solve such issues:
public MyItemType ValidSelectedItem { get; private set; }
public MyItemType SelectedItem
{
get => _SelectedItem;
set {
... your current setter code here ...
// Remember most recent non-null value.
if (value != null)
ValidSelectedItem = value;
}
}
private MyItemType _SelectedItem;
ValidSelectedItem remembers the non-null item, even if xamarin resets the selection back to null. Use it in code that needs that value.
Is there a difference in using "Okay" or "OK" in DisplayPromptAsync ? try to change it in your code.
this is default Page.DisplayPromptAsync Method:
public System.Threading.Tasks.Task<string> DisplayPromptAsync
(
string title,
string message,
string accept = "OK",
string cancel = "Cancel",
string placeholder = default,
int maxLength = -1,
Xamarin.Forms.Keyboard keyboard = default,
string initialValue = ""
);
public Login ClickGetStatus()
{
//IWebElement btnGetStatus = driver.FindElement(By.XPath("//*[contains(#id,'GetStatus')]"));
do
{
buttonName_GetStatus[0] = "abc";
Thread.Sleep(3000);
bool is_displayed =
wrapper.IsElementDisplayed(
driver.FindElement(By.XPath("//*[contains(#id,'GetStatus')]")));
//bool IsElementDisplayed = driver.FindElement(By.XPath("//*[contains(#id,'GetStatus')]")).Displayed;
if (is_displayed)
{
//wrapper.Click(btnExecute);
string getnameofbutton1 =
driver.FindElement(
By.XPath("//*[contains(#id,'GetStatus')]")).GetAttribute("id");
Console.WriteLine("Name of the button is : " + getnameofbutton1);
buttonName_GetStatus = getnameofbutton1.Split('_');
driver.FindElement(
By.XPath("//*[contains(#id,'GetStatus')]")).Click();
}
else
{
Console.WriteLine("Element is not displayed");
}
}
while (buttonName_GetStatus[0] == "GetStatus");
return this;
}
Below is the Logic for the above code
Checks for the button called Get Status
if it finds the button Get Status then clicks on it
i have used contains in the xpath as the element id for that button changes dynamically.
The above code runs fine and clicks on the Get Status button but doesn't come out from the loop when the name of the Get Status button changes to View Result and still searches for Get Status button
If the expected ID of the button after being updated is "ViewResult", then you can update your condition to use that.
while (buttonName_GetStatus[0] != "ViewResult");
This will keep looping round whilst the button does not equal "ViewResult".
Is this the behavior you're trying to achieve?
public Login ClickGetStatus()
{
//IWebElement btnGetStatus = driver.FindElement(By.XPath("//*
[contains(#id,'GetStatus')]"));
do
{
buttonName_GetStatus[0] = "abc";
Thread.Sleep(3000);
var elements = driver.FindElements(By.XPath("//*[contains(#id,'GetStatus')]"));
var is_displayed = elements.Count > 0;
//bool IsElementDisplayed = driver.FindElement(By.XPath("//*[contains(#id,'GetStatus')]")).Displayed;
if (is_displayed)
{
//wrapper.Click(btnExecute);
string getnameofbutton1 =
driver.FindElement(
By.XPath("//*[contains(#id,'GetStatus')]")).GetAttribute("id");
Console.WriteLine("Name of the button is : " + getnameofbutton1);
buttonName_GetStatus = getnameofbutton1.Split('_');
driver.FindElement(
By.XPath("//*[contains(#id,'GetStatus')]")).Click();
}
else
{
Console.WriteLine("Element is not displayed");
}
}
while (buttonName_GetStatus[0] != "ViewResult");
return this;
}
I think problem might be here, especially when you check if isDisplayed == true then this line buttonName_GetStatus = getnameofbutton1.Split('_'); overrides array so that infinitive loop appeared.
I have a list of records with for example status, department, amount, title and some buttons.
If I wanted to assert for example the title I used the following code:
private IWebElement GetTitleElement(int actionRowNumber)
{
var xpath = $"//tr[#id = 'ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__{actionRowNumber}']/td[9]";
return BrowserFactory.Driver.FindElement(By.XPath(xpath));
}
I am doing the same for type, status, department
And then I used a try catch method to go through each record untill I found the desired record in the system:
public void CheckActionxxx(ActionTypes type, Enum.Departments departments, Enum.ActionStatus actionstatus, string title)
{
Wait();
var actiontype = type;
try
{
for (var i = 0; i <= 4; i++)
{
if (GetTitleElement(i).Text == title && GetActionTypeElement(i).Text == actiontype.ToString())
{
Assert.AreEqual(type.ToString(), GetActionTypeElement(i).Text);
Assert.AreEqual(actionstatus.ToString(), GetActionStatusElement(i).Text);
Assert.AreEqual(departments == Enum.Departments.None ? " " : departments.ToString(),
GetActionDepartmentElement(i).Text);
return;
}
}
throw new NoSuchElementException();
}
catch (NoSuchElementException)
{
throw new NoSuchElementException($"Not found with'{title}'");
}
}
Because the id’s only had a difference in numbers (e.g. 0,1,2) I was able to use integer
Department:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__0"]/td[5]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__1"]/td[5]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__2"]/td[5]
Status:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__0"]/td[2]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__1"]/td[2]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__2"]/td[2]
Title:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__0"]/td[9]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__1"]/td[9]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__2"]/td[9]
Now I want to use a try catch that finds a button based on the same way of working but the id of this button is as follow:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl04_ButtonClose"]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl06_ButtonClose"]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl08_ButtonClose"]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl10_ButtonClose"]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl12_ButtonClose"]
As you can see it starts at ctl04 and continues in steps of two.
I cannot figure out how to design my private webelement. I tried:
private IWebElement GetActionCloseButtonElement(int actionRowNumber)
{
var xpath = $"//tr[#id = 'ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_{actionRowNumber}_ButtonClose']";
return BrowserFactory.Driver.FindElement(By.XPath(xpath));
}
But that doesnt work.
Something like this should work.
actionRowNumber should be 04, 06, 08, 10, 12 as from the xpath.
private IWebElement GetActionCloseButtonElement(int actionRowNumber)
{
return BrowserFactory.Driver.FindElement(By.Xpath("//tr[#id = 'ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl"+ actionRowNumber +"_ButtonClose']"));
}
I designed my webpage to read a data string then display the results on labels in an html table. I am attempting to highlight the row that my database reads as a current order. My only problem is only one record is set to be active but they all highlight as if they were active. I use an array to set my data and I also use the label to get the ID I need (all is in code below). I have posted my method and where I use it in the asp page load. How can I fix my method to return correctly?
The implementing of the method in page load
if (lineData.IsCurrentOrderFind(L68.Text))
{
myTable.Rows[1].Cells[0].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[1].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[2].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[3].BgColor = "#FE2E2E";
myTable.Rows[1].Cells[4].BgColor = "#FE2E2E";
}
Here is method that label above gets passed to
public bool IsCurrentOrderFind(string itemNumber)
{
StringBuilder sqlString = new StringBuilder();
sqlString.Append("SELECT * ");
sqlString.Append("FROM WorkOrder ");
sqlString.Append("WHERE LineNumber = " + ConfigurationManager.AppSettings["Line"] + " AND LineCompleted = 0 AND (ScaleGroup LIKE '%1' OR ScaleGroup LIKE '%3') ");
sqlString.Append(" AND CaseGenNum6 = #CaseGenNum6");
SqlDataReader reader = null;
SqlConnection dbConn = App_Code.DBHelper.getConnection();
SqlParameter[] parameters = new SqlParameter[] { new SqlParameter("#CaseGenNum6", itemNumber) };
try
{
reader = App_Code.DBHelper.executeQuery(dbConn, sqlString.ToString(), parameters);
while (reader.Read())
{
IsCurrentOrder = (reader["IsCurrentOrder"] != DBNull.Value && !string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString())) ? true : false;
}
reader.Close();
reader.Dispose();
dbConn.Close();
dbConn.Dispose();
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (dbConn != null)
{
try { dbConn.Close(); dbConn.Dispose(); }
catch { }
}
if (reader != null)
{
try { reader.Close(); reader.Dispose(); }
catch { }
}
}
if (IsCurrentOrder == true) I realize this is not necessary
{
return true;
}
else
{
return false;
}
}
The problem could be with this expression:
!string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString())
Instead of calling ToString(), try simply casting it to a string:
!string.IsNullOrEmpty((string)reader["IsCurrentOrder"])
Possibly even better (the previous line might throw an exception if it's not really a string):
!string.IsNullOrEmpty(reader["IsCurrentOrder"] as string)
The reason being is that if the string is really null, calling ToString() will return a non-null string "null".
IsCurrentOrder is not declared locally. It seems to be declared at a higher scope. When you enter this function, nothing is initializing the variable (back to false). So, it is remaining at its last setting. Try this code instead:
public bool IsCurrentOrderFind(string itemNumber)
{
bool IsCurrentOrder = false;
//and the rest of your source code
the line
IsCurrentOrder = (reader["IsCurrentOrder"] != DBNull.Value && !string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString())) ? true : false;
}
It's not actually checking the value of the field, only that it's not null or empty.
Try
if(
(reader["IsCurrentOrder"] != DBNull.Value
&&
!string.IsNullOrEmpty(reader["IsCurrentOrder"].ToString()))
)
{
IsCurrentOrder = reader["IsCurrentOrder"];
}
else
IsCurrentOrder = false;
I think there is a lot of refactoring you could do to this method though that will simplify the logic.
I have a DataGridView in a Windows Form, it has 2 columns, the last column is going to contain the name of a packet, the point is that this name never has to be duplicated.
I tried with this code using CellValidating event
string value = Convert.ToString(dgvTiendas.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
int cellIndex = e.RowIndex;
if(cellIndex == 1)
{
foreach (DataGridViewRow rw in dgvTiendas.Rows)
{
if (cellIndex == rw.Index)
{
return;
}
else
{
string valorRow = Convert.ToString(rw.Cells["ContenedorCodigoBarras"].Value);
if (value == valorRow)
{
MessageBox.Show("The container is already used");
dgvTiendas.Rows[e.RowIndex].ErrorText = "Contenedor ya utilizado";
e.Cancel = true;
}
else
{
e.Cancel = false;
}
}
}
}
When i run the application and i write a container's name, it is validated but it seems that validate the current cell because the "Error text" appears on the RowHeader.
Please help i have some weeks with this.
You are having this problem because you are setting the error text of the row with this code.
dgvTiendas.Rows[e.RowIndex].ErrorText = "Contenedor ya utilizado";
You need to set error text of the cell
dgvTiendas[e.ColumnIndex, e.RowIndex].ErrorText = "an error occured";