I have a page that is loaded into a frame. in the code behind, i have a string variable called mode. What i want to do is when a hyperlink is clicked, open the page and set the mode
I was hoping to do it declaratively. I tried doing
NavigatUri="myPage?mode=edit"
and then adding the following to the code behind after the initialize component call
mode = this.NavigationContext.QueryString["mode"];
But I was getting a page not found error. I have a feeling I'm on another planet. I'm new to silverlight. How do i navigate to a page in this fashion and pass that argument?
Take a look at the UriMapper in you main page. The final UriMapping would normally be the catch all that looks like this:-
<uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>
You will note the "/" at the beginning of the Uri and the corresponding page belongs in the "/Views" folder.
Use the attribute:-
NavigatUri="/myPage?mode=edit"
make sure your page in the Views folder.
However I'm pretty sure you already have that. Your real problem is your attempt to access the NavigationContext in the execution the page constructor. Its not available at that point in the pages lifecycle. You should not attempt to use it until OnNavigatedTo is executed.
public partial class MyPage : Page
{
public MyPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string mode = null;
if (NavigationContext.QueryString.ContainsKey("mode"))
{
mode = NavigationContext.QueryString["mode"];
}
// Do stuff with mode.
}
}
The reason you are seeing "page not found error" is thats because the Nav apps ErrorWindow just assumes any failure to load a page was because it wasn't found. Which assuming you've coded your pages correctly is probably a reasonable assumption.
Related
Let's consider a two-page Silverlight WP application: the main page PageA, and another PageB we can open from PageA and pass a parameter into it. As Charles Petzold suggests in his bestseller 'Programming WP7', we can instantiate PageB using a statement like this:
NavigationService.Navigate(new Uri(
"/EditEntryPage.xaml?ItemIndex=" + myItemIndex, UriKind.Relative));
And then use the following construct in the OnNavigatedTo/OnNaviagetdFrom events of PageB to process the parameter and the case when the app was tombstoned and reactivated again:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string myParam;
if (this.NavigationContext.QueryString.TryGetValue("ItemIndex", out myParam))
{
fItemIndex = int.Parse(myParam);
}
else if (PhoneApplicationService.Current.State.ContainsKey(APP_STATE_KEY_ITEM_INDEX))
{
fItemIndex = (int)PhoneApplicationService.Current.State[APP_STATE_KEY_ITEM_INDEX];
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
PhoneApplicationService.Current.State[APP_STATE_KEY_ITEM_INDEX] = fItemIndex;
}
However, we have one problem if the user left the app from PageB, the app was tombstoned, and the user returns again to the app to the same PageB using the task manager. In this case, NavigationContext.QueryString in the OnNavigatedTo event returns the same ItemIndex parameter as if the page were called from PageA and the second 'if' is never executed!
Did I miss something important (an app settings, etc), or the behavior was changed in WP8 and we can no longer use this approach?
The query string behavior has not changed from WP7 to WP8. If it is in the uri, it will stay there upon resuming from tombstone or fast app switching.
One method I use to tell the difference is with the NavigationEventArgs.IsNavigationInitiator property. It will be true only when navigating inside your app, and false when you are being resumed from the OS. So if you were to change your first if statment to the following then it may work as you expected:
if (e.IsNavigationInitiator
&& this.NavigationContext.QueryString.TryGetValue("ItemIndex", out myParam))
I´ve a NavigationWindow with some pages. I navigate from one to another with buttons, and go back function of navigation window. My problem is I use a descriptor in some of the pages when they load, and I´d like to dispose it when you use go back function in navigationwindow (in fact the "descriptor" is Kinect, and when the page loads, it starts Kinect with sensor.start(), and I want to stop it when going back, sensor.stop()... but I think it´s the same as a file descriptor for this issue and much more people has worked with file descriptors).
Is there any way to extend the GoBack function in the page to dispose descriptors (in my code I only need to call sensor.stop(); )?
Thanks in advance
My suggestion in the comment was based on windows phone development experience.. but after i tried applying that solution in wpf using navigationwindow, i found nothing like OnNavigatedTo/OnNavigatedFrom in WP/silverlight.
But i found Navigating event of NaviagtionWindow can be used instead. In that event, you can get this.CurrentSource which is Page2 (if you navigate back from Page2 to Page1) and dispose descriptors in that Page.
Hope this work.
Ok, I found how to do a workaround. It also applies to the question: how to dispose an object in WPF. It´s weird all posts about dispose objects in WPF talk about GC and that you can´t dispose it yourself. Yes, GC dispose objects automatically, but when he wants. But maybe you want to dispose inmediately, or you have an object that needs previous operations before dispose. In my case, Kinect needs to be stopped before dispose (you can dispose without stopping, but kinect ir sensor is still working). And GC is not solution because I need to stop it before dispose.
So, the solution:
public partial class MyClass : Page
{
private KinectSensor sensor;
public MyClass()
{
InitializeComponent();
this.Loaded += (s, e) => { NavigationService.Navigating += NavigationService_Navigating; };
// What you want to add to the constructor
// I want to start Kinect
sensor = KinectSensor.KinectSensors.FirstOrDefault(k => k.Status == KinectStatus.Connected);
sensor.Start();
}
public void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back)
{
// What you want to do.
// I want to stop and dispose Kinect
if (sensor != null)
{
sensor.Stop();
sensor.Dispose();
}
}
}
}
Summary
With the PageFactory, how do I ensure the correct page has been passed to the appropriate page object? For example making sure that a real login page is being passed to an instance of the LoginPage object.
Details
I notice on the PageObjects documentation that they explain how, in the constructor, that you can check to see if you are on the right page. For example
// Check that we're on the right page.
if (!"Login".equals(driver.getTitle())) {
// Alternatively, we could navigate to the login page, perhaps logging out first
throw new IllegalStateException("This is not the login page");
}
However, when reading the PageFactory docs, they don't explain how to check if the correct page has been passed in. They just go ahead and attempt to run the test. How can I best check this when using PageFactory?
You could put an assertion in your constructor that checks the URL is valid e.g.
MyPage(WebDriver driver) {
PageFactory.initElements(driver, this);
assert wait.until(currentURIIs(new URI("http://www.mydomain.com/mypage.html")));
}
The above is using the following expected condition:
public static ExpectedCondition<Boolean> currentURIIs(final URI pageURI) {
new ExpectedCondition<Boolean>() {
#Override
Boolean apply(WebDriver driver) {
new URI(driver.currentUrl) == pageURI;
}
}
}
You could of course search for an element you know is on the page, or any other uniquely identifying feature. Checking the current page URI is one possible option, there are many other things you could check to ensure you are on the correct page.
The test should call page.get(). Then the get function will call isLoaded(). If page.isLoaded() doesn't throw an exception, then it will assume that its loaded, and return.
Otherwise, it will call page.load(), and then page.isLoaded() again. (to make sure that its actually loaded).
So each of your classes that extend LoadablePageComponent need to have a isLoaded() and load() function.
Quick question about page objects in selenium webdriver. our site is very dynamic with lots of ajax and various authentication states. It is tough to figure out how to define each page object BUT lets say I have figured that out and defined several page objects that represent our site.
How do you handle crossing from page to page. So I get a page object for my home page and one for my account page and one for my results page. Then I need to write a test that traverses all my pages to simulate a user performing multiple actions.
How do you say give me a HomePage object to create a new use -> then get a account page object to go perform some user actions - then get a result page object to verify those actions all from a single script.
How are people doing this?
thanks
When you're simulating having the user enter a new URL into the URL bar of the browser, then it's the responsibility of the test class to create the page object it needs.
On the other hand, when you're doing some operation on the page that would cause the browser to point to another page -- for example, clicking a link or submitting a form -- then it's the responsibility of that page object to return the next page object.
Since I don't know enough about the relationships between your home page, account page, and result page to tell you exactly how it'd play out in your site, I'll use an online store app as an example instead.
Let's say you've got a SearchPage. When you submit the form on the SearchPage, it returns a ResultsPage. And when you click on a result, you get a ProductPage. So the classes would look something like this (abbreviated to just the relevant methods):
public class SearchPage {
public void open() {
return driver.get(url);
}
public ResultsPage search(String term) {
// Code to enter the term into the search box goes here
// Code to click the submit button goes here
return new ResultsPage();
}
}
public class ResultsPage {
public ProductPage openResult(int resultNumber) {
// Code to locate the relevant result link and click on it
return new ProductPage();
}
}
The test method to execute this story would look something like this:
#Test
public void testSearch() {
// Here we want to simulate the user going to the search page
// as if opening a browser and entering the URL in the address bar.
// So we instantiate it here in the test code.
SearchPage searchPage = new SearchPage();
searchPage.open(); // calls driver.get() on the correct URL
// Now search for "video games"
ResultsPage videoGameResultsPage = searchPage.search("video games");
// Now open the first result
ProductPage firstProductPage = videoGameResultsPage.openResult(0);
// Some assertion would probably go here
}
So as you can see, there's this "chaining" of Page Objects where each one returns the next one.
The result is that you end up with lots of different page objects instantiating other page objects. So if you've got a site of any considerable size, you could consider using a dependency injection framework for creating those page objects.
Well, I created my own Java classes which represent the pages:
Say, the below is code to represent home page. Here user can login:
public class HomePage{
private WebDriver driver;
private WebElement loginInput;
private WebElement passwordInput;
private WebElement loginSubmit;
public WebDriver getDriver(){
return driver;
}
public HomePage(){
driver = new FirefoxDriver();
}
public CustomerPage login(String username, String password){
driver.get("http://the-test-page.com");
loginInput = driver.findElement(By.id("username"));
loginInput.sendKeys(username);
passwordInput = driver.findElement(By.id("password"));
passwordInput.sendKeys(password);
loginSubmit = driver.findElement(By.id("login"));
loginSubmit.click();
return new CustomerPage(this);
}
}
And the page for Customer can look like this. Here I am demonstrating, how to get, say, logged in user:
public class CustomerPage{
private HomePage homePage;
private WebElement loggedInUserSpan;
public CustomerPage(HomePage hp){
this.homePage = hp;
}
public String getLoggedInUser(){
loggedInUserSpan = homePage.getDriver().findElement(By.id("usrLongName"));
return loggedInUserSpan.getText();
}
}
And the test can go like this:
#Test
public void testLogin(){
HomePage home = new HomePage();
CustomerPage customer = home.login("janipav", "extrasecretpassword");
Assert.assertEquals(customer.getLoggedInUser(), "Pavel Janicek");
}
You generally want to model what a user actually does when using your site. This ends up taking the form of a Domain Specific Language (DSL) when using page objects. It gets confusing with reusable page components though.
Now that Java 8 is out with default methods, reusable page components can be treated as mixins using default methods. I have a blog post with some code samples found here that explains this in more detail: http://blog.jsdevel.me/2015/04/pageobjects-done-right-in-java-8.html
I suggest you use a framework that provides support for these patterns. Geb is one of the best one out there. Below is an example taken from their manual
Browser.drive {
to LoginPage
assert at(LoginPage)
loginForm.with {
username = "admin"
password = "password"
}
loginButton.click()
assert at(AdminPage)
}
class LoginPage extends Page {
static url = "http://myapp.com/login"
static at = { heading.text() == "Please Login" }
static content = {
heading { $("h1") }
loginForm { $("form.login") }
loginButton(to: AdminPage) { loginForm.login() }
}
}
class AdminPage extends Page {
static at = { heading.text() == "Admin Section" }
static content = {
heading { $("h1") }
}
}
I enjoy writing Selenium Webdriver tests using the Page Object pattern. But was personally annoyed at the verbosity and repetition of having to always explicitly instantiate and return the next page or page component. So with the benefit of Python's metaclasses I wrote a library, called Keteparaha, that automatically figures out what should be returned from a selenium page object's method calls.
Silverlight 3 allows you to run your application out of the browser, which installs a link on your desktop/start menu.
The problem is we are currently using
System.Windows.Browser.HtmlPage.
Window.Navigate(new Uri("http://<server>/<resource>"), "_blank")
to load a URL into a new browser window (it's to provide a 'print friendly' page for users to print). This works in the normal SL in-browser version, but outside the browser we get 'The DOM/scripting bridge is disabled.' exception thrown when issuing the call.
Is there an alternative which works out of the browser?
I've seen Open page in silverlight out of browser but I need to do this entirely in code, so I don't want to add a (hidden) hyperlink button and then programmatically 'click' it (unless I absolutely have to...).
you can try inheriting from HyperlinkButton and exposing public Click() method (which you can then instantiate and call from code instead of declaring it in xaml).
Details here: http://mokosh.co.uk/post/2009/10/08/silverlight-oob-open-new-browser-window/
I wrote an Extension method based on the idea to inherit from the HyperlinkButton.
public static class UriExtensions {
class Clicker : HyperlinkButton {
public void DoClick() {
base.OnClick();
}
}
static readonly Clicker clicker = new Clicker();
public static void Navigate(this Uri uri) {
Navigate(uri, "_self");
}
public static void Navigate(this Uri uri, string targetName) {
clicker.NavigateUri = uri;
clicker.TargetName = targetName;
clicker.DoClick();
}
}
Then use can use it simple, like
new Uri("http://www.google.com").Navigate("_blank");