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 = ""
);
Related
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'm having issues with displaying the variable within a Message box. What I want to do is display in a messagebox which Combobox hasn't been filled in, it will display this in a list within the messagebox and then stop the user from saving to the database. The error is stating that it is a use of an unassigned variable but I have assigned it at the top of the 'if' statement.
private void btnSaveDB_Click(object sender, EventArgs e)
{
if (cmbPolType.SelectedItem == null ||
cmbPolNum.SelectedItem == null ||
cmbTPReg.SelectedItem == null ||
cmbLossType.SelectedItem == null ||
cmbLossDesc.SelectedItem == null ||
cmbInsdFault.SelectedItem == null)
{
string polType, polNum, lossType, lossDesc, tpReg, insdFault = null;
if (cmbPolType.SelectedItem==null)
{
polType = "Policy Type";
}
if (cmbPolNum.SelectedItem==null)
{
polNum = "Policy Number";
}
if (cmbLossType.SelectedItem==null)
{
lossType = "Loss Type";
}
if (cmbLossDesc.SelectedItem ==null)
{
lossDesc = "Loss Description";
}
if (cmbTPReg.SelectedItem==null)
{
tpReg = "TP Reg";
}
if (cmbInsdFault.SelectedItem==null)
{
insdFault = "Insd at Fault";
}
MessageBox.Show("You have not selected options for the following: " + lossDesc );
}
No lossDesc is not initialized in that way as well as the other strings variables but the insdFault. (The error message points to lossDesc because is the only one used in the remainder of the code).
Instead of initializing each one, I suggest to use a simple List<string> where you add your error messages and type all of them at the end of the test
List<string> missingData = new List<string>();
if (cmbPolType.SelectedItem == null)
missingData.Add("Policy Type");
if (cmbPolNum.SelectedItem == null)
missingData.Add("Policy Number");
if (cmbLossType.SelectedItem == null)
missingData.Add("Loss Type");
if (cmbLossDesc.SelectedItem == null)
missingData.Add("Loss Description");
if (cmbTPReg.SelectedItem == null)
missingData.Add("TP Reg");
if (cmbInsdFault.SelectedItem == null)
missingData.Add("Insd at Fault");
if(missingData.Count > 0)
{
MessageBox.Show("You have not selected options for the following: " +
Environment.NewLine +
string.Join(Environment.NewLine, missingData.ToArray()));
}
else
{
... save to database ? ....
}
This removes the need to use and initialize a bunch of string variables and uses the string.Join method to get the whole error message in a single string with each error on a separate line.
So I have a WPF window. There are TextBoxes "Login" and "Ip Address" which are binded to "Login" and "IpAddress" properties. What I need is to save property Login into database as login#ipAddress.
I tried this, but it goes wrong:
public string Login
{
get { return _TModel.Login; }
set
{
if (value == _TModel.Login)
return;
_TModel.Login = value + "#" + IpAddress;
base.OnPropertyChanged("Login");
}
}
How can I do that? BTW I'm using NHibernate to work with the DB.
Thank you.
Replace # with "#":
public string Login
{
get { return _TModel.Login; }
set
{
if (value == _TModel.Login)
return;
value = string.Empty;
_TModel.Login = value + "#" + IpAddress;
base.OnPropertyChanged("Login");
}
}
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.");
}